blob: 6b9f232e8f7dcc23a558d7ff764a2628f487d170 [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
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010019#include "arch/arm/asm_support_arm.h"
Calin Juravle34166012014-12-19 17:22:29 +000020#include "arch/arm/instruction_set_features_arm.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070021#include "art_method.h"
Andreas Gampe5678db52017-06-08 14:11:18 -070022#include "base/bit_utils.h"
23#include "base/bit_utils_iterator.h"
Zheng Xuc6667102015-05-15 16:08:45 +080024#include "code_generator_utils.h"
Anton Kirilov74234da2017-01-13 14:42:47 +000025#include "common_arm.h"
Vladimir Marko58155012015-08-19 12:49:41 +000026#include "compiled_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070027#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010028#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080029#include "intrinsics.h"
30#include "intrinsics_arm.h"
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010031#include "linker/arm/relative_patcher_thumb2.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070032#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070033#include "mirror/class-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070034#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010035#include "utils/arm/assembler_arm.h"
36#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000037#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000039
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000040namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010041
Roland Levillain3b359c72015-11-17 19:35:12 +000042template<class MirrorType>
43class GcRoot;
44
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000045namespace arm {
46
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000047static bool ExpectedPairLayout(Location location) {
48 // We expected this for both core and fpu register pairs.
49 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
50}
51
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010052static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010053
David Brazdil58282f42016-01-14 12:45:10 +000054static constexpr Register kCoreAlwaysSpillRegister = R5;
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000055static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070056 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000057static constexpr SRegister kFpuCalleeSaves[] =
58 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010059
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000060// D31 cannot be split into two S registers, and the register allocator only works on
61// S registers. Therefore there is no need to block it.
62static constexpr DRegister DTMP = D31;
63
Vladimir Markof3e0ee22015-12-17 15:23:13 +000064static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070065
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010066// Reference load (except object array loads) is using LDR Rt, [Rn, #offset] which can handle
67// offset < 4KiB. For offsets >= 4KiB, the load shall be emitted as two or more instructions.
68// For the Baker read barrier implementation using link-generated thunks we need to split
69// the offset explicitly.
70constexpr uint32_t kReferenceLoadMinFarOffset = 4 * KB;
71
72// Flags controlling the use of link-time generated thunks for Baker read barriers.
73constexpr bool kBakerReadBarrierLinkTimeThunksEnableForFields = true;
74constexpr bool kBakerReadBarrierLinkTimeThunksEnableForArrays = true;
75constexpr bool kBakerReadBarrierLinkTimeThunksEnableForGcRoots = true;
76
77// The reserved entrypoint register for link-time generated thunks.
78const Register kBakerCcEntrypointRegister = R4;
79
Roland Levillain7cbd27f2016-08-11 23:53:33 +010080// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
81#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070082#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010083
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010084static inline void CheckLastTempIsBakerCcEntrypointRegister(HInstruction* instruction) {
85 DCHECK_EQ(static_cast<uint32_t>(kBakerCcEntrypointRegister),
86 linker::Thumb2RelativePatcher::kBakerCcEntrypointRegister);
87 DCHECK_NE(instruction->GetLocations()->GetTempCount(), 0u);
88 DCHECK_EQ(kBakerCcEntrypointRegister,
89 instruction->GetLocations()->GetTemp(
90 instruction->GetLocations()->GetTempCount() - 1u).AsRegister<Register>());
91}
92
93static inline void EmitPlaceholderBne(CodeGeneratorARM* codegen, Label* bne_label) {
Vladimir Marko88abba22017-05-03 17:09:25 +010094 ScopedForce32Bit force_32bit(down_cast<Thumb2Assembler*>(codegen->GetAssembler()));
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010095 __ BindTrackedLabel(bne_label);
96 Label placeholder_label;
97 __ b(&placeholder_label, NE); // Placeholder, patched at link-time.
98 __ Bind(&placeholder_label);
99}
100
Vladimir Marko88abba22017-05-03 17:09:25 +0100101static inline bool CanEmitNarrowLdr(Register rt, Register rn, uint32_t offset) {
102 return ArmAssembler::IsLowRegister(rt) && ArmAssembler::IsLowRegister(rn) && offset < 32u;
103}
104
Artem Serovf4d6aee2016-07-11 10:41:45 +0100105static constexpr int kRegListThreshold = 4;
106
Artem Serovd300d8f2016-07-15 14:00:56 +0100107// SaveLiveRegisters and RestoreLiveRegisters from SlowPathCodeARM operate on sets of S registers,
108// for each live D registers they treat two corresponding S registers as live ones.
109//
110// Two following functions (SaveContiguousSRegisterList, RestoreContiguousSRegisterList) build
111// from a list of contiguous S registers a list of contiguous D registers (processing first/last
112// S registers corner cases) and save/restore this new list treating them as D registers.
113// - decreasing code size
114// - avoiding hazards on Cortex-A57, when a pair of S registers for an actual live D register is
115// restored and then used in regular non SlowPath code as D register.
116//
117// For the following example (v means the S register is live):
118// D names: | D0 | D1 | D2 | D4 | ...
119// S names: | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | ...
120// Live? | | v | v | v | v | v | v | | ...
121//
122// S1 and S6 will be saved/restored independently; D registers list (D1, D2) will be processed
123// as D registers.
124static size_t SaveContiguousSRegisterList(size_t first,
125 size_t last,
126 CodeGenerator* codegen,
127 size_t stack_offset) {
128 DCHECK_LE(first, last);
129 if ((first == last) && (first == 0)) {
130 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first);
131 return stack_offset;
132 }
133 if (first % 2 == 1) {
134 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first++);
135 }
136
137 bool save_last = false;
138 if (last % 2 == 0) {
139 save_last = true;
140 --last;
141 }
142
143 if (first < last) {
144 DRegister d_reg = static_cast<DRegister>(first / 2);
145 DCHECK_EQ((last - first + 1) % 2, 0u);
146 size_t number_of_d_regs = (last - first + 1) / 2;
147
148 if (number_of_d_regs == 1) {
Scott Wakelinga7812ae2016-10-17 10:03:36 +0100149 __ StoreDToOffset(d_reg, SP, stack_offset);
Artem Serovd300d8f2016-07-15 14:00:56 +0100150 } else if (number_of_d_regs > 1) {
151 __ add(IP, SP, ShifterOperand(stack_offset));
152 __ vstmiad(IP, d_reg, number_of_d_regs);
153 }
154 stack_offset += number_of_d_regs * kArmWordSize * 2;
155 }
156
157 if (save_last) {
158 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, last + 1);
159 }
160
161 return stack_offset;
162}
163
164static size_t RestoreContiguousSRegisterList(size_t first,
165 size_t last,
166 CodeGenerator* codegen,
167 size_t stack_offset) {
168 DCHECK_LE(first, last);
169 if ((first == last) && (first == 0)) {
170 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first);
171 return stack_offset;
172 }
173 if (first % 2 == 1) {
174 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first++);
175 }
176
177 bool restore_last = false;
178 if (last % 2 == 0) {
179 restore_last = true;
180 --last;
181 }
182
183 if (first < last) {
184 DRegister d_reg = static_cast<DRegister>(first / 2);
185 DCHECK_EQ((last - first + 1) % 2, 0u);
186 size_t number_of_d_regs = (last - first + 1) / 2;
187 if (number_of_d_regs == 1) {
188 __ LoadDFromOffset(d_reg, SP, stack_offset);
189 } else if (number_of_d_regs > 1) {
190 __ add(IP, SP, ShifterOperand(stack_offset));
191 __ vldmiad(IP, d_reg, number_of_d_regs);
192 }
193 stack_offset += number_of_d_regs * kArmWordSize * 2;
194 }
195
196 if (restore_last) {
197 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, last + 1);
198 }
199
200 return stack_offset;
201}
202
Artem Serovf4d6aee2016-07-11 10:41:45 +0100203void SlowPathCodeARM::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
204 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
205 size_t orig_offset = stack_offset;
206
207 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
208 for (uint32_t i : LowToHighBits(core_spills)) {
209 // If the register holds an object, update the stack mask.
210 if (locations->RegisterContainsObject(i)) {
211 locations->SetStackBit(stack_offset / kVRegSize);
212 }
213 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
214 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
215 saved_core_stack_offsets_[i] = stack_offset;
216 stack_offset += kArmWordSize;
217 }
218
219 int reg_num = POPCOUNT(core_spills);
220 if (reg_num != 0) {
221 if (reg_num > kRegListThreshold) {
222 __ StoreList(RegList(core_spills), orig_offset);
223 } else {
224 stack_offset = orig_offset;
225 for (uint32_t i : LowToHighBits(core_spills)) {
226 stack_offset += codegen->SaveCoreRegister(stack_offset, i);
227 }
228 }
229 }
230
Artem Serovd300d8f2016-07-15 14:00:56 +0100231 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
232 orig_offset = stack_offset;
Vladimir Marko804b03f2016-09-14 16:26:36 +0100233 for (uint32_t i : LowToHighBits(fp_spills)) {
Artem Serovf4d6aee2016-07-11 10:41:45 +0100234 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
235 saved_fpu_stack_offsets_[i] = stack_offset;
Artem Serovd300d8f2016-07-15 14:00:56 +0100236 stack_offset += kArmWordSize;
Artem Serovf4d6aee2016-07-11 10:41:45 +0100237 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100238
239 stack_offset = orig_offset;
240 while (fp_spills != 0u) {
241 uint32_t begin = CTZ(fp_spills);
242 uint32_t tmp = fp_spills + (1u << begin);
243 fp_spills &= tmp; // Clear the contiguous range of 1s.
244 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
245 stack_offset = SaveContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
246 }
247 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100248}
249
250void SlowPathCodeARM::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
251 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
252 size_t orig_offset = stack_offset;
253
254 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
255 for (uint32_t i : LowToHighBits(core_spills)) {
256 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
257 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
258 stack_offset += kArmWordSize;
259 }
260
261 int reg_num = POPCOUNT(core_spills);
262 if (reg_num != 0) {
263 if (reg_num > kRegListThreshold) {
264 __ LoadList(RegList(core_spills), orig_offset);
265 } else {
266 stack_offset = orig_offset;
267 for (uint32_t i : LowToHighBits(core_spills)) {
268 stack_offset += codegen->RestoreCoreRegister(stack_offset, i);
269 }
270 }
271 }
272
Artem Serovd300d8f2016-07-15 14:00:56 +0100273 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
274 while (fp_spills != 0u) {
275 uint32_t begin = CTZ(fp_spills);
276 uint32_t tmp = fp_spills + (1u << begin);
277 fp_spills &= tmp; // Clear the contiguous range of 1s.
278 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
279 stack_offset = RestoreContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
Artem Serovf4d6aee2016-07-11 10:41:45 +0100280 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100281 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100282}
283
284class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100285 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100286 explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100287
Alexandre Rames67555f72014-11-18 10:55:16 +0000288 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100289 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100290 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000291 if (instruction_->CanThrowIntoCatchBlock()) {
292 // Live registers will be restored in the catch block if caught.
293 SaveLiveRegisters(codegen, instruction_->GetLocations());
294 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100295 arm_codegen->InvokeRuntime(kQuickThrowNullPointer,
296 instruction_,
297 instruction_->GetDexPc(),
298 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000299 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100300 }
301
Alexandre Rames8158f282015-08-07 10:26:17 +0100302 bool IsFatal() const OVERRIDE { return true; }
303
Alexandre Rames9931f312015-06-19 14:47:01 +0100304 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
305
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100306 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100307 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
308};
309
Artem Serovf4d6aee2016-07-11 10:41:45 +0100310class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
Calin Juravled0d48522014-11-04 16:40:20 +0000311 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100312 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCodeARM(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000313
Alexandre Rames67555f72014-11-18 10:55:16 +0000314 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000315 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
316 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100317 arm_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000318 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000319 }
320
Alexandre Rames8158f282015-08-07 10:26:17 +0100321 bool IsFatal() const OVERRIDE { return true; }
322
Alexandre Rames9931f312015-06-19 14:47:01 +0100323 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
324
Calin Juravled0d48522014-11-04 16:40:20 +0000325 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000326 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
327};
328
Artem Serovf4d6aee2016-07-11 10:41:45 +0100329class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000330 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000331 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100332 : SlowPathCodeARM(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000333
Alexandre Rames67555f72014-11-18 10:55:16 +0000334 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100335 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000336 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100337 arm_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000338 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100339 if (successor_ == nullptr) {
340 __ b(GetReturnLabel());
341 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100342 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100343 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000344 }
345
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100346 Label* GetReturnLabel() {
347 DCHECK(successor_ == nullptr);
348 return &return_label_;
349 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000350
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100351 HBasicBlock* GetSuccessor() const {
352 return successor_;
353 }
354
Alexandre Rames9931f312015-06-19 14:47:01 +0100355 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
356
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000357 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100358 // If not null, the block to branch to after the suspend check.
359 HBasicBlock* const successor_;
360
361 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000362 Label return_label_;
363
364 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
365};
366
Artem Serovf4d6aee2016-07-11 10:41:45 +0100367class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100368 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100369 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100370 : SlowPathCodeARM(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100371
Alexandre Rames67555f72014-11-18 10:55:16 +0000372 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100373 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100374 LocationSummary* locations = instruction_->GetLocations();
375
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100376 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000377 if (instruction_->CanThrowIntoCatchBlock()) {
378 // Live registers will be restored in the catch block if caught.
379 SaveLiveRegisters(codegen, instruction_->GetLocations());
380 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000381 // We're moving two locations to locations that could overlap, so we need a parallel
382 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100383 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000384 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100385 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000386 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100387 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100388 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100389 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
390 Primitive::kPrimInt);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100391 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
392 ? kQuickThrowStringBounds
393 : kQuickThrowArrayBounds;
394 arm_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100395 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000396 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100397 }
398
Alexandre Rames8158f282015-08-07 10:26:17 +0100399 bool IsFatal() const OVERRIDE { return true; }
400
Alexandre Rames9931f312015-06-19 14:47:01 +0100401 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
402
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100403 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100404 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
405};
406
Artem Serovf4d6aee2016-07-11 10:41:45 +0100407class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100408 public:
Vladimir Markoea4c1262017-02-06 19:59:33 +0000409 LoadClassSlowPathARM(HLoadClass* cls, HInstruction* at, uint32_t dex_pc, bool do_clinit)
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000410 : SlowPathCodeARM(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000411 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
412 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100413
Alexandre Rames67555f72014-11-18 10:55:16 +0000414 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000415 LocationSummary* locations = instruction_->GetLocations();
Vladimir Markoea4c1262017-02-06 19:59:33 +0000416 Location out = locations->Out();
417 constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000418
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100419 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
420 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000421 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100422
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100423 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoea4c1262017-02-06 19:59:33 +0000424 // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
425 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
426 bool is_load_class_bss_entry =
427 (cls_ == instruction_) && (cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry);
428 Register entry_address = kNoRegister;
429 if (is_load_class_bss_entry && call_saves_everything_except_r0) {
430 Register temp = locations->GetTemp(0).AsRegister<Register>();
431 // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
432 // the kSaveEverything call.
433 bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
434 entry_address = temp_is_r0 ? out.AsRegister<Register>() : temp;
435 DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
436 if (temp_is_r0) {
437 __ mov(entry_address, ShifterOperand(temp));
438 }
439 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000440 dex::TypeIndex type_index = cls_->GetTypeIndex();
441 __ LoadImmediate(calling_convention.GetRegisterAt(0), type_index.index_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100442 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
443 : kQuickInitializeType;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000444 arm_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000445 if (do_clinit_) {
446 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
447 } else {
448 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
449 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000450
Vladimir Markoea4c1262017-02-06 19:59:33 +0000451 // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
452 if (is_load_class_bss_entry) {
453 if (call_saves_everything_except_r0) {
454 // The class entry address was preserved in `entry_address` thanks to kSaveEverything.
455 __ str(R0, Address(entry_address));
456 } else {
457 // For non-Baker read barrier, we need to re-calculate the address of the string entry.
458 Register temp = IP;
459 CodeGeneratorARM::PcRelativePatchInfo* labels =
460 arm_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
461 __ BindTrackedLabel(&labels->movw_label);
462 __ movw(temp, /* placeholder */ 0u);
463 __ BindTrackedLabel(&labels->movt_label);
464 __ movt(temp, /* placeholder */ 0u);
465 __ BindTrackedLabel(&labels->add_pc_label);
466 __ add(temp, temp, ShifterOperand(PC));
467 __ str(R0, Address(temp));
468 }
469 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000470 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000471 if (out.IsValid()) {
472 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000473 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
474 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000475 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100476 __ b(GetExitLabel());
477 }
478
Alexandre Rames9931f312015-06-19 14:47:01 +0100479 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
480
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100481 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000482 // The class this slow path will load.
483 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100484
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000485 // The dex PC of `at_`.
486 const uint32_t dex_pc_;
487
488 // Whether to initialize the class.
489 const bool do_clinit_;
490
491 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100492};
493
Vladimir Markoaad75c62016-10-03 08:46:48 +0000494class LoadStringSlowPathARM : public SlowPathCodeARM {
495 public:
496 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCodeARM(instruction) {}
497
498 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Markoea4c1262017-02-06 19:59:33 +0000499 DCHECK(instruction_->IsLoadString());
500 DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000501 LocationSummary* locations = instruction_->GetLocations();
502 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100503 HLoadString* load = instruction_->AsLoadString();
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000504 const dex::StringIndex string_index = load->GetStringIndex();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100505 Register out = locations->Out().AsRegister<Register>();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100506 constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000507
508 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
509 __ Bind(GetEntryLabel());
510 SaveLiveRegisters(codegen, locations);
511
512 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100513 // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
Vladimir Markoea4c1262017-02-06 19:59:33 +0000514 // the kSaveEverything call.
515 Register entry_address = kNoRegister;
516 if (call_saves_everything_except_r0) {
517 Register temp = locations->GetTemp(0).AsRegister<Register>();
518 bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
519 entry_address = temp_is_r0 ? out : temp;
520 DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
521 if (temp_is_r0) {
522 __ mov(entry_address, ShifterOperand(temp));
523 }
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100524 }
525
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000526 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index.index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000527 arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
528 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100529
530 // Store the resolved String to the .bss entry.
531 if (call_saves_everything_except_r0) {
532 // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
533 __ str(R0, Address(entry_address));
534 } else {
535 // For non-Baker read barrier, we need to re-calculate the address of the string entry.
Vladimir Markoea4c1262017-02-06 19:59:33 +0000536 Register temp = IP;
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100537 CodeGeneratorARM::PcRelativePatchInfo* labels =
538 arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
539 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000540 __ movw(temp, /* placeholder */ 0u);
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100541 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000542 __ movt(temp, /* placeholder */ 0u);
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100543 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000544 __ add(temp, temp, ShifterOperand(PC));
545 __ str(R0, Address(temp));
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100546 }
547
Vladimir Markoaad75c62016-10-03 08:46:48 +0000548 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000549 RestoreLiveRegisters(codegen, locations);
550
Vladimir Markoaad75c62016-10-03 08:46:48 +0000551 __ b(GetExitLabel());
552 }
553
554 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
555
556 private:
557 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
558};
559
Artem Serovf4d6aee2016-07-11 10:41:45 +0100560class TypeCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000561 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000562 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100563 : SlowPathCodeARM(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000564
Alexandre Rames67555f72014-11-18 10:55:16 +0000565 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000566 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000567 DCHECK(instruction_->IsCheckCast()
568 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000569
570 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
571 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000572
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000573 if (!is_fatal_) {
574 SaveLiveRegisters(codegen, locations);
575 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000576
577 // We're moving two locations to locations that could overlap, so we need a parallel
578 // move resolver.
579 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800580 codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800581 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
582 Primitive::kPrimNot,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800583 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800584 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
585 Primitive::kPrimNot);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000586 if (instruction_->IsInstanceOf()) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100587 arm_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100588 instruction_,
589 instruction_->GetDexPc(),
590 this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800591 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000592 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
593 } else {
594 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800595 arm_codegen->InvokeRuntime(kQuickCheckInstanceOf,
596 instruction_,
597 instruction_->GetDexPc(),
598 this);
599 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000600 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000601
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000602 if (!is_fatal_) {
603 RestoreLiveRegisters(codegen, locations);
604 __ b(GetExitLabel());
605 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000606 }
607
Alexandre Rames9931f312015-06-19 14:47:01 +0100608 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
609
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000610 bool IsFatal() const OVERRIDE { return is_fatal_; }
611
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000612 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000613 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000614
615 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
616};
617
Artem Serovf4d6aee2016-07-11 10:41:45 +0100618class DeoptimizationSlowPathARM : public SlowPathCodeARM {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700619 public:
Aart Bik42249c32016-01-07 15:33:50 -0800620 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100621 : SlowPathCodeARM(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700622
623 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800624 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700625 __ Bind(GetEntryLabel());
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100626 LocationSummary* locations = instruction_->GetLocations();
627 SaveLiveRegisters(codegen, locations);
628 InvokeRuntimeCallingConvention calling_convention;
629 __ LoadImmediate(calling_convention.GetRegisterAt(0),
630 static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100631 arm_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100632 CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700633 }
634
Alexandre Rames9931f312015-06-19 14:47:01 +0100635 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
636
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700637 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700638 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
639};
640
Artem Serovf4d6aee2016-07-11 10:41:45 +0100641class ArraySetSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100642 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100643 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100644
645 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
646 LocationSummary* locations = instruction_->GetLocations();
647 __ Bind(GetEntryLabel());
648 SaveLiveRegisters(codegen, locations);
649
650 InvokeRuntimeCallingConvention calling_convention;
651 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
652 parallel_move.AddMove(
653 locations->InAt(0),
654 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
655 Primitive::kPrimNot,
656 nullptr);
657 parallel_move.AddMove(
658 locations->InAt(1),
659 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
660 Primitive::kPrimInt,
661 nullptr);
662 parallel_move.AddMove(
663 locations->InAt(2),
664 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
665 Primitive::kPrimNot,
666 nullptr);
667 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
668
669 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100670 arm_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000671 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100672 RestoreLiveRegisters(codegen, locations);
673 __ b(GetExitLabel());
674 }
675
676 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
677
678 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100679 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
680};
681
Roland Levillain54f869e2017-03-06 13:54:11 +0000682// Abstract base class for read barrier slow paths marking a reference
683// `ref`.
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000684//
Roland Levillain54f869e2017-03-06 13:54:11 +0000685// Argument `entrypoint` must be a register location holding the read
686// barrier marking runtime entry point to be invoked.
687class ReadBarrierMarkSlowPathBaseARM : public SlowPathCodeARM {
688 protected:
689 ReadBarrierMarkSlowPathBaseARM(HInstruction* instruction, Location ref, Location entrypoint)
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000690 : SlowPathCodeARM(instruction), ref_(ref), entrypoint_(entrypoint) {
691 DCHECK(kEmitCompilerReadBarrier);
692 }
693
Roland Levillain54f869e2017-03-06 13:54:11 +0000694 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathBaseARM"; }
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000695
Roland Levillain54f869e2017-03-06 13:54:11 +0000696 // Generate assembly code calling the read barrier marking runtime
697 // entry point (ReadBarrierMarkRegX).
698 void GenerateReadBarrierMarkRuntimeCall(CodeGenerator* codegen) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000699 Register ref_reg = ref_.AsRegister<Register>();
Roland Levillain47b3ab22017-02-27 14:31:35 +0000700
Roland Levillain47b3ab22017-02-27 14:31:35 +0000701 // No need to save live registers; it's taken care of by the
702 // entrypoint. Also, there is no need to update the stack mask,
703 // as this runtime call will not trigger a garbage collection.
704 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
705 DCHECK_NE(ref_reg, SP);
706 DCHECK_NE(ref_reg, LR);
707 DCHECK_NE(ref_reg, PC);
708 // IP is used internally by the ReadBarrierMarkRegX entry point
709 // as a temporary, it cannot be the entry point's input/output.
710 DCHECK_NE(ref_reg, IP);
711 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCoreRegisters) << ref_reg;
712 // "Compact" slow path, saving two moves.
713 //
714 // Instead of using the standard runtime calling convention (input
715 // and output in R0):
716 //
717 // R0 <- ref
718 // R0 <- ReadBarrierMark(R0)
719 // ref <- R0
720 //
721 // we just use rX (the register containing `ref`) as input and output
722 // of a dedicated entrypoint:
723 //
724 // rX <- ReadBarrierMarkRegX(rX)
725 //
726 if (entrypoint_.IsValid()) {
727 arm_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
728 __ blx(entrypoint_.AsRegister<Register>());
729 } else {
Roland Levillain54f869e2017-03-06 13:54:11 +0000730 // Entrypoint is not already loaded, load from the thread.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000731 int32_t entry_point_offset =
732 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref_reg);
733 // This runtime call does not require a stack map.
734 arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
735 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000736 }
737
738 // The location (register) of the marked object reference.
739 const Location ref_;
740
741 // The location of the entrypoint if it is already loaded.
742 const Location entrypoint_;
743
744 private:
745 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathBaseARM);
746};
747
Dave Allison20dfc792014-06-16 20:44:29 -0700748// Slow path marking an object reference `ref` during a read
749// barrier. The field `obj.field` in the object `obj` holding this
Roland Levillain54f869e2017-03-06 13:54:11 +0000750// reference does not get updated by this slow path after marking.
Dave Allison20dfc792014-06-16 20:44:29 -0700751//
752// This means that after the execution of this slow path, `ref` will
753// always be up-to-date, but `obj.field` may not; i.e., after the
754// flip, `ref` will be a to-space reference, but `obj.field` will
755// probably still be a from-space reference (unless it gets updated by
756// another thread, or if another thread installed another object
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000757// reference (different from `ref`) in `obj.field`).
758//
759// If `entrypoint` is a valid location it is assumed to already be
760// holding the entrypoint. The case where the entrypoint is passed in
Roland Levillainba650a42017-03-06 13:52:32 +0000761// is when the decision to mark is based on whether the GC is marking.
Roland Levillain54f869e2017-03-06 13:54:11 +0000762class ReadBarrierMarkSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000763 public:
764 ReadBarrierMarkSlowPathARM(HInstruction* instruction,
765 Location ref,
766 Location entrypoint = Location::NoLocation())
Roland Levillain54f869e2017-03-06 13:54:11 +0000767 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000768 DCHECK(kEmitCompilerReadBarrier);
769 }
770
771 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
772
773 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
774 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain54f869e2017-03-06 13:54:11 +0000775 DCHECK(locations->CanCall());
776 if (kIsDebugBuild) {
777 Register ref_reg = ref_.AsRegister<Register>();
778 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
779 }
780 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
781 << "Unexpected instruction in read barrier marking slow path: "
782 << instruction_->DebugName();
783
784 __ Bind(GetEntryLabel());
785 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000786 __ b(GetExitLabel());
787 }
788
789 private:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000790 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
791};
792
Roland Levillain54f869e2017-03-06 13:54:11 +0000793// Slow path loading `obj`'s lock word, loading a reference from
794// object `*(obj + offset + (index << scale_factor))` into `ref`, and
795// marking `ref` if `obj` is gray according to the lock word (Baker
796// read barrier). The field `obj.field` in the object `obj` holding
797// this reference does not get updated by this slow path after marking
798// (see LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
799// below for that).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000800//
Roland Levillain54f869e2017-03-06 13:54:11 +0000801// This means that after the execution of this slow path, `ref` will
802// always be up-to-date, but `obj.field` may not; i.e., after the
803// flip, `ref` will be a to-space reference, but `obj.field` will
804// probably still be a from-space reference (unless it gets updated by
805// another thread, or if another thread installed another object
806// reference (different from `ref`) in `obj.field`).
807//
808// Argument `entrypoint` must be a register location holding the read
809// barrier marking runtime entry point to be invoked.
810class LoadReferenceWithBakerReadBarrierSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000811 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000812 LoadReferenceWithBakerReadBarrierSlowPathARM(HInstruction* instruction,
813 Location ref,
814 Register obj,
815 uint32_t offset,
816 Location index,
817 ScaleFactor scale_factor,
818 bool needs_null_check,
819 Register temp,
820 Location entrypoint)
821 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000822 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000823 offset_(offset),
824 index_(index),
825 scale_factor_(scale_factor),
826 needs_null_check_(needs_null_check),
827 temp_(temp) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000828 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000829 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000830 }
831
Roland Levillain54f869e2017-03-06 13:54:11 +0000832 const char* GetDescription() const OVERRIDE {
833 return "LoadReferenceWithBakerReadBarrierSlowPathARM";
834 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000835
836 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
837 LocationSummary* locations = instruction_->GetLocations();
838 Register ref_reg = ref_.AsRegister<Register>();
839 DCHECK(locations->CanCall());
840 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000841 DCHECK_NE(ref_reg, temp_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000842 DCHECK(instruction_->IsInstanceFieldGet() ||
843 instruction_->IsStaticFieldGet() ||
844 instruction_->IsArrayGet() ||
845 instruction_->IsArraySet() ||
Roland Levillain47b3ab22017-02-27 14:31:35 +0000846 instruction_->IsInstanceOf() ||
847 instruction_->IsCheckCast() ||
848 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
849 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
850 << "Unexpected instruction in read barrier marking slow path: "
851 << instruction_->DebugName();
852 // The read barrier instrumentation of object ArrayGet
853 // instructions does not support the HIntermediateAddress
854 // instruction.
855 DCHECK(!(instruction_->IsArrayGet() &&
856 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
857
858 __ Bind(GetEntryLabel());
Roland Levillain54f869e2017-03-06 13:54:11 +0000859
860 // When using MaybeGenerateReadBarrierSlow, the read barrier call is
861 // inserted after the original load. However, in fast path based
862 // Baker's read barriers, we need to perform the load of
863 // mirror::Object::monitor_ *before* the original reference load.
864 // This load-load ordering is required by the read barrier.
Roland Levillainff487002017-03-07 16:50:01 +0000865 // The slow path (for Baker's algorithm) should look like:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000866 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000867 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
868 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
869 // HeapReference<mirror::Object> ref = *src; // Original reference load.
870 // bool is_gray = (rb_state == ReadBarrier::GrayState());
871 // if (is_gray) {
872 // ref = entrypoint(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
873 // }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000874 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000875 // Note: the original implementation in ReadBarrier::Barrier is
876 // slightly more complex as it performs additional checks that we do
877 // not do here for performance reasons.
878
879 // /* int32_t */ monitor = obj->monitor_
880 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
881 __ LoadFromOffset(kLoadWord, temp_, obj_, monitor_offset);
882 if (needs_null_check_) {
883 codegen->MaybeRecordImplicitNullCheck(instruction_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000884 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000885 // /* LockWord */ lock_word = LockWord(monitor)
886 static_assert(sizeof(LockWord) == sizeof(int32_t),
887 "art::LockWord and int32_t have different sizes.");
888
889 // Introduce a dependency on the lock_word including the rb_state,
890 // which shall prevent load-load reordering without using
891 // a memory barrier (which would be more expensive).
892 // `obj` is unchanged by this operation, but its value now depends
893 // on `temp`.
894 __ add(obj_, obj_, ShifterOperand(temp_, LSR, 32));
895
896 // The actual reference load.
897 // A possible implicit null check has already been handled above.
898 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
899 arm_codegen->GenerateRawReferenceLoad(
900 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
901
902 // Mark the object `ref` when `obj` is gray.
903 //
904 // if (rb_state == ReadBarrier::GrayState())
905 // ref = ReadBarrier::Mark(ref);
906 //
907 // Given the numeric representation, it's enough to check the low bit of the
908 // rb_state. We do that by shifting the bit out of the lock word with LSRS
909 // which can be a 16-bit instruction unlike the TST immediate.
910 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
911 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
912 __ Lsrs(temp_, temp_, LockWord::kReadBarrierStateShift + 1);
913 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
914 GenerateReadBarrierMarkRuntimeCall(codegen);
915
Roland Levillain47b3ab22017-02-27 14:31:35 +0000916 __ b(GetExitLabel());
917 }
918
919 private:
Roland Levillain54f869e2017-03-06 13:54:11 +0000920 // The register containing the object holding the marked object reference field.
921 Register obj_;
922 // The offset, index and scale factor to access the reference in `obj_`.
923 uint32_t offset_;
924 Location index_;
925 ScaleFactor scale_factor_;
926 // Is a null check required?
927 bool needs_null_check_;
928 // A temporary register used to hold the lock word of `obj_`.
929 Register temp_;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000930
Roland Levillain54f869e2017-03-06 13:54:11 +0000931 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierSlowPathARM);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000932};
933
Roland Levillain54f869e2017-03-06 13:54:11 +0000934// Slow path loading `obj`'s lock word, loading a reference from
935// object `*(obj + offset + (index << scale_factor))` into `ref`, and
936// marking `ref` if `obj` is gray according to the lock word (Baker
937// read barrier). If needed, this slow path also atomically updates
938// the field `obj.field` in the object `obj` holding this reference
939// after marking (contrary to
940// LoadReferenceWithBakerReadBarrierSlowPathARM above, which never
941// tries to update `obj.field`).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000942//
943// This means that after the execution of this slow path, both `ref`
944// and `obj.field` will be up-to-date; i.e., after the flip, both will
945// hold the same to-space reference (unless another thread installed
946// another object reference (different from `ref`) in `obj.field`).
Roland Levillainba650a42017-03-06 13:52:32 +0000947//
Roland Levillain54f869e2017-03-06 13:54:11 +0000948// Argument `entrypoint` must be a register location holding the read
949// barrier marking runtime entry point to be invoked.
950class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
951 : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000952 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000953 LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(HInstruction* instruction,
954 Location ref,
955 Register obj,
956 uint32_t offset,
957 Location index,
958 ScaleFactor scale_factor,
959 bool needs_null_check,
960 Register temp1,
961 Register temp2,
962 Location entrypoint)
963 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000964 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000965 offset_(offset),
966 index_(index),
967 scale_factor_(scale_factor),
968 needs_null_check_(needs_null_check),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000969 temp1_(temp1),
Roland Levillain54f869e2017-03-06 13:54:11 +0000970 temp2_(temp2) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000971 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000972 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000973 }
974
Roland Levillain54f869e2017-03-06 13:54:11 +0000975 const char* GetDescription() const OVERRIDE {
976 return "LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM";
977 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000978
979 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
980 LocationSummary* locations = instruction_->GetLocations();
981 Register ref_reg = ref_.AsRegister<Register>();
982 DCHECK(locations->CanCall());
983 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000984 DCHECK_NE(ref_reg, temp1_);
985
986 // This slow path is only used by the UnsafeCASObject intrinsic at the moment.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000987 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
988 << "Unexpected instruction in read barrier marking and field updating slow path: "
989 << instruction_->DebugName();
990 DCHECK(instruction_->GetLocations()->Intrinsified());
991 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
Roland Levillain54f869e2017-03-06 13:54:11 +0000992 DCHECK_EQ(offset_, 0u);
993 DCHECK_EQ(scale_factor_, ScaleFactor::TIMES_1);
994 // The location of the offset of the marked reference field within `obj_`.
995 Location field_offset = index_;
996 DCHECK(field_offset.IsRegisterPair()) << field_offset;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000997
998 __ Bind(GetEntryLabel());
999
Roland Levillainff487002017-03-07 16:50:01 +00001000 // The implementation is similar to LoadReferenceWithBakerReadBarrierSlowPathARM's:
1001 //
1002 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
1003 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
1004 // HeapReference<mirror::Object> ref = *src; // Original reference load.
1005 // bool is_gray = (rb_state == ReadBarrier::GrayState());
1006 // if (is_gray) {
1007 // old_ref = ref;
1008 // ref = entrypoint(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
1009 // compareAndSwapObject(obj, field_offset, old_ref, ref);
1010 // }
1011
Roland Levillain54f869e2017-03-06 13:54:11 +00001012 // /* int32_t */ monitor = obj->monitor_
1013 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
1014 __ LoadFromOffset(kLoadWord, temp1_, obj_, monitor_offset);
1015 if (needs_null_check_) {
1016 codegen->MaybeRecordImplicitNullCheck(instruction_);
1017 }
1018 // /* LockWord */ lock_word = LockWord(monitor)
1019 static_assert(sizeof(LockWord) == sizeof(int32_t),
1020 "art::LockWord and int32_t have different sizes.");
1021
1022 // Introduce a dependency on the lock_word including the rb_state,
1023 // which shall prevent load-load reordering without using
1024 // a memory barrier (which would be more expensive).
1025 // `obj` is unchanged by this operation, but its value now depends
1026 // on `temp1`.
1027 __ add(obj_, obj_, ShifterOperand(temp1_, LSR, 32));
1028
1029 // The actual reference load.
1030 // A possible implicit null check has already been handled above.
1031 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1032 arm_codegen->GenerateRawReferenceLoad(
1033 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
1034
1035 // Mark the object `ref` when `obj` is gray.
1036 //
1037 // if (rb_state == ReadBarrier::GrayState())
1038 // ref = ReadBarrier::Mark(ref);
1039 //
1040 // Given the numeric representation, it's enough to check the low bit of the
1041 // rb_state. We do that by shifting the bit out of the lock word with LSRS
1042 // which can be a 16-bit instruction unlike the TST immediate.
1043 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
1044 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
1045 __ Lsrs(temp1_, temp1_, LockWord::kReadBarrierStateShift + 1);
1046 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
1047
1048 // Save the old value of the reference before marking it.
Roland Levillain47b3ab22017-02-27 14:31:35 +00001049 // Note that we cannot use IP to save the old reference, as IP is
1050 // used internally by the ReadBarrierMarkRegX entry point, and we
1051 // need the old reference after the call to that entry point.
1052 DCHECK_NE(temp1_, IP);
1053 __ Mov(temp1_, ref_reg);
Roland Levillain27b1f9c2017-01-17 16:56:34 +00001054
Roland Levillain54f869e2017-03-06 13:54:11 +00001055 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001056
1057 // If the new reference is different from the old reference,
Roland Levillain54f869e2017-03-06 13:54:11 +00001058 // update the field in the holder (`*(obj_ + field_offset)`).
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001059 //
1060 // Note that this field could also hold a different object, if
1061 // another thread had concurrently changed it. In that case, the
1062 // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set
1063 // (CAS) operation below would abort the CAS, leaving the field
1064 // as-is.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001065 __ cmp(temp1_, ShifterOperand(ref_reg));
Roland Levillain54f869e2017-03-06 13:54:11 +00001066 __ b(GetExitLabel(), EQ);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001067
1068 // Update the the holder's field atomically. This may fail if
1069 // mutator updates before us, but it's OK. This is achieved
1070 // using a strong compare-and-set (CAS) operation with relaxed
1071 // memory synchronization ordering, where the expected value is
1072 // the old reference and the desired value is the new reference.
1073
1074 // Convenience aliases.
1075 Register base = obj_;
1076 // The UnsafeCASObject intrinsic uses a register pair as field
1077 // offset ("long offset"), of which only the low part contains
1078 // data.
Roland Levillain54f869e2017-03-06 13:54:11 +00001079 Register offset = field_offset.AsRegisterPairLow<Register>();
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001080 Register expected = temp1_;
1081 Register value = ref_reg;
1082 Register tmp_ptr = IP; // Pointer to actual memory.
1083 Register tmp = temp2_; // Value in memory.
1084
1085 __ add(tmp_ptr, base, ShifterOperand(offset));
1086
1087 if (kPoisonHeapReferences) {
1088 __ PoisonHeapReference(expected);
1089 if (value == expected) {
1090 // Do not poison `value`, as it is the same register as
1091 // `expected`, which has just been poisoned.
1092 } else {
1093 __ PoisonHeapReference(value);
1094 }
1095 }
1096
1097 // do {
1098 // tmp = [r_ptr] - expected;
1099 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
1100
Roland Levillain24a4d112016-10-26 13:10:46 +01001101 Label loop_head, exit_loop;
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001102 __ Bind(&loop_head);
1103
1104 __ ldrex(tmp, tmp_ptr);
1105
1106 __ subs(tmp, tmp, ShifterOperand(expected));
1107
Roland Levillain24a4d112016-10-26 13:10:46 +01001108 __ it(NE);
1109 __ clrex(NE);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001110
Roland Levillain24a4d112016-10-26 13:10:46 +01001111 __ b(&exit_loop, NE);
1112
1113 __ strex(tmp, value, tmp_ptr);
1114 __ cmp(tmp, ShifterOperand(1));
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001115 __ b(&loop_head, EQ);
1116
Roland Levillain24a4d112016-10-26 13:10:46 +01001117 __ Bind(&exit_loop);
1118
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001119 if (kPoisonHeapReferences) {
1120 __ UnpoisonHeapReference(expected);
1121 if (value == expected) {
1122 // Do not unpoison `value`, as it is the same register as
1123 // `expected`, which has just been unpoisoned.
1124 } else {
1125 __ UnpoisonHeapReference(value);
1126 }
1127 }
1128
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001129 __ b(GetExitLabel());
1130 }
1131
1132 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001133 // The register containing the object holding the marked object reference field.
1134 const Register obj_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001135 // The offset, index and scale factor to access the reference in `obj_`.
1136 uint32_t offset_;
1137 Location index_;
1138 ScaleFactor scale_factor_;
1139 // Is a null check required?
1140 bool needs_null_check_;
1141 // A temporary register used to hold the lock word of `obj_`; and
1142 // also to hold the original reference value, when the reference is
1143 // marked.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001144 const Register temp1_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001145 // A temporary register used in the implementation of the CAS, to
1146 // update the object's reference field.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001147 const Register temp2_;
1148
Roland Levillain54f869e2017-03-06 13:54:11 +00001149 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001150};
1151
Roland Levillain3b359c72015-11-17 19:35:12 +00001152// Slow path generating a read barrier for a heap reference.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001153class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001154 public:
1155 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
1156 Location out,
1157 Location ref,
1158 Location obj,
1159 uint32_t offset,
1160 Location index)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001161 : SlowPathCodeARM(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +00001162 out_(out),
1163 ref_(ref),
1164 obj_(obj),
1165 offset_(offset),
1166 index_(index) {
1167 DCHECK(kEmitCompilerReadBarrier);
1168 // If `obj` is equal to `out` or `ref`, it means the initial object
1169 // has been overwritten by (or after) the heap object reference load
1170 // to be instrumented, e.g.:
1171 //
1172 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00001173 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001174 //
1175 // In that case, we have lost the information about the original
1176 // object, and the emitted read barrier cannot work properly.
1177 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
1178 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
1179 }
1180
1181 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1182 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1183 LocationSummary* locations = instruction_->GetLocations();
1184 Register reg_out = out_.AsRegister<Register>();
1185 DCHECK(locations->CanCall());
1186 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +01001187 DCHECK(instruction_->IsInstanceFieldGet() ||
1188 instruction_->IsStaticFieldGet() ||
1189 instruction_->IsArrayGet() ||
1190 instruction_->IsInstanceOf() ||
1191 instruction_->IsCheckCast() ||
Andreas Gamped9911ee2017-03-27 13:27:24 -07001192 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
Roland Levillainc9285912015-12-18 10:38:42 +00001193 << "Unexpected instruction in read barrier for heap reference slow path: "
1194 << instruction_->DebugName();
Roland Levillain19c54192016-11-04 13:44:09 +00001195 // The read barrier instrumentation of object ArrayGet
1196 // instructions does not support the HIntermediateAddress
1197 // instruction.
1198 DCHECK(!(instruction_->IsArrayGet() &&
1199 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
Roland Levillain3b359c72015-11-17 19:35:12 +00001200
1201 __ Bind(GetEntryLabel());
1202 SaveLiveRegisters(codegen, locations);
1203
1204 // We may have to change the index's value, but as `index_` is a
1205 // constant member (like other "inputs" of this slow path),
1206 // introduce a copy of it, `index`.
1207 Location index = index_;
1208 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +01001209 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +00001210 if (instruction_->IsArrayGet()) {
1211 // Compute the actual memory offset and store it in `index`.
1212 Register index_reg = index_.AsRegister<Register>();
1213 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
1214 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
1215 // We are about to change the value of `index_reg` (see the
1216 // calls to art::arm::Thumb2Assembler::Lsl and
1217 // art::arm::Thumb2Assembler::AddConstant below), but it has
1218 // not been saved by the previous call to
1219 // art::SlowPathCode::SaveLiveRegisters, as it is a
1220 // callee-save register --
1221 // art::SlowPathCode::SaveLiveRegisters does not consider
1222 // callee-save registers, as it has been designed with the
1223 // assumption that callee-save registers are supposed to be
1224 // handled by the called function. So, as a callee-save
1225 // register, `index_reg` _would_ eventually be saved onto
1226 // the stack, but it would be too late: we would have
1227 // changed its value earlier. Therefore, we manually save
1228 // it here into another freely available register,
1229 // `free_reg`, chosen of course among the caller-save
1230 // registers (as a callee-save `free_reg` register would
1231 // exhibit the same problem).
1232 //
1233 // Note we could have requested a temporary register from
1234 // the register allocator instead; but we prefer not to, as
1235 // this is a slow path, and we know we can find a
1236 // caller-save register that is available.
1237 Register free_reg = FindAvailableCallerSaveRegister(codegen);
1238 __ Mov(free_reg, index_reg);
1239 index_reg = free_reg;
1240 index = Location::RegisterLocation(index_reg);
1241 } else {
1242 // The initial register stored in `index_` has already been
1243 // saved in the call to art::SlowPathCode::SaveLiveRegisters
1244 // (as it is not a callee-save register), so we can freely
1245 // use it.
1246 }
1247 // Shifting the index value contained in `index_reg` by the scale
1248 // factor (2) cannot overflow in practice, as the runtime is
1249 // unable to allocate object arrays with a size larger than
1250 // 2^26 - 1 (that is, 2^28 - 4 bytes).
1251 __ Lsl(index_reg, index_reg, TIMES_4);
1252 static_assert(
1253 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
1254 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
1255 __ AddConstant(index_reg, index_reg, offset_);
1256 } else {
Roland Levillain3d312422016-06-23 13:53:42 +01001257 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
1258 // intrinsics, `index_` is not shifted by a scale factor of 2
1259 // (as in the case of ArrayGet), as it is actually an offset
1260 // to an object field within an object.
1261 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001262 DCHECK(instruction_->GetLocations()->Intrinsified());
1263 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
1264 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
1265 << instruction_->AsInvoke()->GetIntrinsic();
1266 DCHECK_EQ(offset_, 0U);
1267 DCHECK(index_.IsRegisterPair());
1268 // UnsafeGet's offset location is a register pair, the low
1269 // part contains the correct offset.
1270 index = index_.ToLow();
1271 }
1272 }
1273
1274 // We're moving two or three locations to locations that could
1275 // overlap, so we need a parallel move resolver.
1276 InvokeRuntimeCallingConvention calling_convention;
1277 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
1278 parallel_move.AddMove(ref_,
1279 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
1280 Primitive::kPrimNot,
1281 nullptr);
1282 parallel_move.AddMove(obj_,
1283 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
1284 Primitive::kPrimNot,
1285 nullptr);
1286 if (index.IsValid()) {
1287 parallel_move.AddMove(index,
1288 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
1289 Primitive::kPrimInt,
1290 nullptr);
1291 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1292 } else {
1293 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1294 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
1295 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001296 arm_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
Roland Levillain3b359c72015-11-17 19:35:12 +00001297 CheckEntrypointTypes<
1298 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
1299 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1300
1301 RestoreLiveRegisters(codegen, locations);
1302 __ b(GetExitLabel());
1303 }
1304
1305 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
1306
1307 private:
1308 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
1309 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
1310 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
1311 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
1312 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
1313 return static_cast<Register>(i);
1314 }
1315 }
1316 // We shall never fail to find a free caller-save register, as
1317 // there are more than two core caller-save registers on ARM
1318 // (meaning it is possible to find one which is different from
1319 // `ref` and `obj`).
1320 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
1321 LOG(FATAL) << "Could not find a free caller-save register";
1322 UNREACHABLE();
1323 }
1324
Roland Levillain3b359c72015-11-17 19:35:12 +00001325 const Location out_;
1326 const Location ref_;
1327 const Location obj_;
1328 const uint32_t offset_;
1329 // An additional location containing an index to an array.
1330 // Only used for HArrayGet and the UnsafeGetObject &
1331 // UnsafeGetObjectVolatile intrinsics.
1332 const Location index_;
1333
1334 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
1335};
1336
1337// Slow path generating a read barrier for a GC root.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001338class ReadBarrierForRootSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001339 public:
1340 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001341 : SlowPathCodeARM(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +00001342 DCHECK(kEmitCompilerReadBarrier);
1343 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001344
1345 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1346 LocationSummary* locations = instruction_->GetLocations();
1347 Register reg_out = out_.AsRegister<Register>();
1348 DCHECK(locations->CanCall());
1349 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +00001350 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
1351 << "Unexpected instruction in read barrier for GC root slow path: "
1352 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001353
1354 __ Bind(GetEntryLabel());
1355 SaveLiveRegisters(codegen, locations);
1356
1357 InvokeRuntimeCallingConvention calling_convention;
1358 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1359 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001360 arm_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain3b359c72015-11-17 19:35:12 +00001361 instruction_,
1362 instruction_->GetDexPc(),
1363 this);
1364 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
1365 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1366
1367 RestoreLiveRegisters(codegen, locations);
1368 __ b(GetExitLabel());
1369 }
1370
1371 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
1372
1373 private:
Roland Levillain3b359c72015-11-17 19:35:12 +00001374 const Location out_;
1375 const Location root_;
1376
1377 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
1378};
1379
Aart Bike9f37602015-10-09 11:15:55 -07001380inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001381 switch (cond) {
1382 case kCondEQ: return EQ;
1383 case kCondNE: return NE;
1384 case kCondLT: return LT;
1385 case kCondLE: return LE;
1386 case kCondGT: return GT;
1387 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -07001388 case kCondB: return LO;
1389 case kCondBE: return LS;
1390 case kCondA: return HI;
1391 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001392 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001393 LOG(FATAL) << "Unreachable";
1394 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001395}
1396
Aart Bike9f37602015-10-09 11:15:55 -07001397// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001398inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001399 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001400 case kCondEQ: return EQ;
1401 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -07001402 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001403 case kCondLT: return LO;
1404 case kCondLE: return LS;
1405 case kCondGT: return HI;
1406 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -07001407 // Unsigned remain unchanged.
1408 case kCondB: return LO;
1409 case kCondBE: return LS;
1410 case kCondA: return HI;
1411 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001412 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001413 LOG(FATAL) << "Unreachable";
1414 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001415}
1416
Vladimir Markod6e069b2016-01-18 11:11:01 +00001417inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
1418 // The ARM condition codes can express all the necessary branches, see the
1419 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
1420 // There is no dex instruction or HIR that would need the missing conditions
1421 // "equal or unordered" or "not equal".
1422 switch (cond) {
1423 case kCondEQ: return EQ;
1424 case kCondNE: return NE /* unordered */;
1425 case kCondLT: return gt_bias ? CC : LT /* unordered */;
1426 case kCondLE: return gt_bias ? LS : LE /* unordered */;
1427 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
1428 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
1429 default:
1430 LOG(FATAL) << "UNREACHABLE";
1431 UNREACHABLE();
1432 }
1433}
1434
Anton Kirilov74234da2017-01-13 14:42:47 +00001435inline Shift ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
1436 switch (op_kind) {
1437 case HDataProcWithShifterOp::kASR: return ASR;
1438 case HDataProcWithShifterOp::kLSL: return LSL;
1439 case HDataProcWithShifterOp::kLSR: return LSR;
1440 default:
1441 LOG(FATAL) << "Unexpected op kind " << op_kind;
1442 UNREACHABLE();
1443 }
1444}
1445
1446static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
1447 Register out,
1448 Register first,
1449 const ShifterOperand& second,
1450 CodeGeneratorARM* codegen) {
1451 if (second.IsImmediate() && second.GetImmediate() == 0) {
1452 const ShifterOperand in = kind == HInstruction::kAnd
1453 ? ShifterOperand(0)
1454 : ShifterOperand(first);
1455
1456 __ mov(out, in);
1457 } else {
1458 switch (kind) {
1459 case HInstruction::kAdd:
1460 __ add(out, first, second);
1461 break;
1462 case HInstruction::kAnd:
1463 __ and_(out, first, second);
1464 break;
1465 case HInstruction::kOr:
1466 __ orr(out, first, second);
1467 break;
1468 case HInstruction::kSub:
1469 __ sub(out, first, second);
1470 break;
1471 case HInstruction::kXor:
1472 __ eor(out, first, second);
1473 break;
1474 default:
1475 LOG(FATAL) << "Unexpected instruction kind: " << kind;
1476 UNREACHABLE();
1477 }
1478 }
1479}
1480
1481static void GenerateDataProc(HInstruction::InstructionKind kind,
1482 const Location& out,
1483 const Location& first,
1484 const ShifterOperand& second_lo,
1485 const ShifterOperand& second_hi,
1486 CodeGeneratorARM* codegen) {
1487 const Register first_hi = first.AsRegisterPairHigh<Register>();
1488 const Register first_lo = first.AsRegisterPairLow<Register>();
1489 const Register out_hi = out.AsRegisterPairHigh<Register>();
1490 const Register out_lo = out.AsRegisterPairLow<Register>();
1491
1492 if (kind == HInstruction::kAdd) {
1493 __ adds(out_lo, first_lo, second_lo);
1494 __ adc(out_hi, first_hi, second_hi);
1495 } else if (kind == HInstruction::kSub) {
1496 __ subs(out_lo, first_lo, second_lo);
1497 __ sbc(out_hi, first_hi, second_hi);
1498 } else {
1499 GenerateDataProcInstruction(kind, out_lo, first_lo, second_lo, codegen);
1500 GenerateDataProcInstruction(kind, out_hi, first_hi, second_hi, codegen);
1501 }
1502}
1503
1504static ShifterOperand GetShifterOperand(Register rm, Shift shift, uint32_t shift_imm) {
1505 return shift_imm == 0 ? ShifterOperand(rm) : ShifterOperand(rm, shift, shift_imm);
1506}
1507
1508static void GenerateLongDataProc(HDataProcWithShifterOp* instruction, CodeGeneratorARM* codegen) {
1509 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
1510 DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
1511
1512 const LocationSummary* const locations = instruction->GetLocations();
1513 const uint32_t shift_value = instruction->GetShiftAmount();
1514 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
1515 const Location first = locations->InAt(0);
1516 const Location second = locations->InAt(1);
1517 const Location out = locations->Out();
1518 const Register first_hi = first.AsRegisterPairHigh<Register>();
1519 const Register first_lo = first.AsRegisterPairLow<Register>();
1520 const Register out_hi = out.AsRegisterPairHigh<Register>();
1521 const Register out_lo = out.AsRegisterPairLow<Register>();
1522 const Register second_hi = second.AsRegisterPairHigh<Register>();
1523 const Register second_lo = second.AsRegisterPairLow<Register>();
1524 const Shift shift = ShiftFromOpKind(instruction->GetOpKind());
1525
1526 if (shift_value >= 32) {
1527 if (shift == LSL) {
1528 GenerateDataProcInstruction(kind,
1529 out_hi,
1530 first_hi,
1531 ShifterOperand(second_lo, LSL, shift_value - 32),
1532 codegen);
1533 GenerateDataProcInstruction(kind,
1534 out_lo,
1535 first_lo,
1536 ShifterOperand(0),
1537 codegen);
1538 } else if (shift == ASR) {
1539 GenerateDataProc(kind,
1540 out,
1541 first,
1542 GetShifterOperand(second_hi, ASR, shift_value - 32),
1543 ShifterOperand(second_hi, ASR, 31),
1544 codegen);
1545 } else {
1546 DCHECK_EQ(shift, LSR);
1547 GenerateDataProc(kind,
1548 out,
1549 first,
1550 GetShifterOperand(second_hi, LSR, shift_value - 32),
1551 ShifterOperand(0),
1552 codegen);
1553 }
1554 } else {
1555 DCHECK_GT(shift_value, 1U);
1556 DCHECK_LT(shift_value, 32U);
1557
1558 if (shift == LSL) {
1559 // We are not doing this for HInstruction::kAdd because the output will require
1560 // Location::kOutputOverlap; not applicable to other cases.
1561 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1562 GenerateDataProcInstruction(kind,
1563 out_hi,
1564 first_hi,
1565 ShifterOperand(second_hi, LSL, shift_value),
1566 codegen);
1567 GenerateDataProcInstruction(kind,
1568 out_hi,
1569 out_hi,
1570 ShifterOperand(second_lo, LSR, 32 - shift_value),
1571 codegen);
1572 GenerateDataProcInstruction(kind,
1573 out_lo,
1574 first_lo,
1575 ShifterOperand(second_lo, LSL, shift_value),
1576 codegen);
1577 } else {
1578 __ Lsl(IP, second_hi, shift_value);
1579 __ orr(IP, IP, ShifterOperand(second_lo, LSR, 32 - shift_value));
1580 GenerateDataProc(kind,
1581 out,
1582 first,
1583 ShifterOperand(second_lo, LSL, shift_value),
1584 ShifterOperand(IP),
1585 codegen);
1586 }
1587 } else {
1588 DCHECK(shift == ASR || shift == LSR);
1589
1590 // We are not doing this for HInstruction::kAdd because the output will require
1591 // Location::kOutputOverlap; not applicable to other cases.
1592 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1593 GenerateDataProcInstruction(kind,
1594 out_lo,
1595 first_lo,
1596 ShifterOperand(second_lo, LSR, shift_value),
1597 codegen);
1598 GenerateDataProcInstruction(kind,
1599 out_lo,
1600 out_lo,
1601 ShifterOperand(second_hi, LSL, 32 - shift_value),
1602 codegen);
1603 GenerateDataProcInstruction(kind,
1604 out_hi,
1605 first_hi,
1606 ShifterOperand(second_hi, shift, shift_value),
1607 codegen);
1608 } else {
1609 __ Lsr(IP, second_lo, shift_value);
1610 __ orr(IP, IP, ShifterOperand(second_hi, LSL, 32 - shift_value));
1611 GenerateDataProc(kind,
1612 out,
1613 first,
1614 ShifterOperand(IP),
1615 ShifterOperand(second_hi, shift, shift_value),
1616 codegen);
1617 }
1618 }
1619 }
1620}
1621
Donghui Bai426b49c2016-11-08 14:55:38 +08001622static void GenerateVcmp(HInstruction* instruction, CodeGeneratorARM* codegen) {
1623 Primitive::Type type = instruction->InputAt(0)->GetType();
1624 Location lhs_loc = instruction->GetLocations()->InAt(0);
1625 Location rhs_loc = instruction->GetLocations()->InAt(1);
1626 if (rhs_loc.IsConstant()) {
1627 // 0.0 is the only immediate that can be encoded directly in
1628 // a VCMP instruction.
1629 //
1630 // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
1631 // specify that in a floating-point comparison, positive zero
1632 // and negative zero are considered equal, so we can use the
1633 // literal 0.0 for both cases here.
1634 //
1635 // Note however that some methods (Float.equal, Float.compare,
1636 // Float.compareTo, Double.equal, Double.compare,
1637 // Double.compareTo, Math.max, Math.min, StrictMath.max,
1638 // StrictMath.min) consider 0.0 to be (strictly) greater than
1639 // -0.0. So if we ever translate calls to these methods into a
1640 // HCompare instruction, we must handle the -0.0 case with
1641 // care here.
1642 DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
1643 if (type == Primitive::kPrimFloat) {
1644 __ vcmpsz(lhs_loc.AsFpuRegister<SRegister>());
1645 } else {
1646 DCHECK_EQ(type, Primitive::kPrimDouble);
1647 __ vcmpdz(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()));
1648 }
1649 } else {
1650 if (type == Primitive::kPrimFloat) {
1651 __ vcmps(lhs_loc.AsFpuRegister<SRegister>(), rhs_loc.AsFpuRegister<SRegister>());
1652 } else {
1653 DCHECK_EQ(type, Primitive::kPrimDouble);
1654 __ vcmpd(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()),
1655 FromLowSToD(rhs_loc.AsFpuRegisterPairLow<SRegister>()));
1656 }
1657 }
1658}
1659
Anton Kirilov5601d4e2017-05-11 19:33:50 +01001660static int64_t AdjustConstantForCondition(int64_t value,
1661 IfCondition* condition,
1662 IfCondition* opposite) {
1663 if (value == 1) {
1664 if (*condition == kCondB) {
1665 value = 0;
1666 *condition = kCondEQ;
1667 *opposite = kCondNE;
1668 } else if (*condition == kCondAE) {
1669 value = 0;
1670 *condition = kCondNE;
1671 *opposite = kCondEQ;
1672 }
1673 } else if (value == -1) {
1674 if (*condition == kCondGT) {
1675 value = 0;
1676 *condition = kCondGE;
1677 *opposite = kCondLT;
1678 } else if (*condition == kCondLE) {
1679 value = 0;
1680 *condition = kCondLT;
1681 *opposite = kCondGE;
1682 }
1683 }
1684
1685 return value;
1686}
1687
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001688static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* condition,
1689 bool invert,
1690 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001691 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1692
1693 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001694 IfCondition cond = condition->GetCondition();
1695 IfCondition opposite = condition->GetOppositeCondition();
1696
1697 if (invert) {
1698 std::swap(cond, opposite);
1699 }
1700
Anton Kirilov5601d4e2017-05-11 19:33:50 +01001701 std::pair<Condition, Condition> ret(EQ, NE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001702 const Location left = locations->InAt(0);
1703 const Location right = locations->InAt(1);
1704
1705 DCHECK(right.IsConstant());
1706
1707 const Register left_high = left.AsRegisterPairHigh<Register>();
1708 const Register left_low = left.AsRegisterPairLow<Register>();
Anton Kirilov5601d4e2017-05-11 19:33:50 +01001709 int64_t value = AdjustConstantForCondition(right.GetConstant()->AsLongConstant()->GetValue(),
1710 &cond,
1711 &opposite);
1712
1713 // Comparisons against 0 are common enough to deserve special attention.
1714 if (value == 0) {
1715 switch (cond) {
1716 case kCondNE:
1717 // x > 0 iff x != 0 when the comparison is unsigned.
1718 case kCondA:
1719 ret = std::make_pair(NE, EQ);
1720 FALLTHROUGH_INTENDED;
1721 case kCondEQ:
1722 // x <= 0 iff x == 0 when the comparison is unsigned.
1723 case kCondBE:
1724 __ orrs(IP, left_low, ShifterOperand(left_high));
1725 return ret;
1726 case kCondLT:
1727 case kCondGE:
1728 __ cmp(left_high, ShifterOperand(0));
1729 return std::make_pair(ARMCondition(cond), ARMCondition(opposite));
1730 // Trivially true or false.
1731 case kCondB:
1732 ret = std::make_pair(NE, EQ);
1733 FALLTHROUGH_INTENDED;
1734 case kCondAE:
1735 __ cmp(left_low, ShifterOperand(left_low));
1736 return ret;
1737 default:
1738 break;
1739 }
1740 }
Donghui Bai426b49c2016-11-08 14:55:38 +08001741
1742 switch (cond) {
1743 case kCondEQ:
1744 case kCondNE:
1745 case kCondB:
1746 case kCondBE:
1747 case kCondA:
1748 case kCondAE:
1749 __ CmpConstant(left_high, High32Bits(value));
1750 __ it(EQ);
1751 __ cmp(left_low, ShifterOperand(Low32Bits(value)), EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001752 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001753 break;
1754 case kCondLE:
1755 case kCondGT:
1756 // Trivially true or false.
1757 if (value == std::numeric_limits<int64_t>::max()) {
1758 __ cmp(left_low, ShifterOperand(left_low));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001759 ret = cond == kCondLE ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
Donghui Bai426b49c2016-11-08 14:55:38 +08001760 break;
1761 }
1762
1763 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001764 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001765 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001766 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001767 } else {
1768 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001769 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001770 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001771 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001772 }
1773
1774 value++;
1775 FALLTHROUGH_INTENDED;
1776 case kCondGE:
1777 case kCondLT:
1778 __ CmpConstant(left_low, Low32Bits(value));
1779 __ sbcs(IP, left_high, ShifterOperand(High32Bits(value)));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001780 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001781 break;
1782 default:
1783 LOG(FATAL) << "Unreachable";
1784 UNREACHABLE();
1785 }
1786
1787 return ret;
1788}
1789
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001790static std::pair<Condition, Condition> GenerateLongTest(HCondition* condition,
1791 bool invert,
1792 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001793 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1794
1795 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001796 IfCondition cond = condition->GetCondition();
1797 IfCondition opposite = condition->GetOppositeCondition();
1798
1799 if (invert) {
1800 std::swap(cond, opposite);
1801 }
1802
1803 std::pair<Condition, Condition> ret;
Donghui Bai426b49c2016-11-08 14:55:38 +08001804 Location left = locations->InAt(0);
1805 Location right = locations->InAt(1);
1806
1807 DCHECK(right.IsRegisterPair());
1808
1809 switch (cond) {
1810 case kCondEQ:
1811 case kCondNE:
1812 case kCondB:
1813 case kCondBE:
1814 case kCondA:
1815 case kCondAE:
1816 __ cmp(left.AsRegisterPairHigh<Register>(),
1817 ShifterOperand(right.AsRegisterPairHigh<Register>()));
1818 __ it(EQ);
1819 __ cmp(left.AsRegisterPairLow<Register>(),
1820 ShifterOperand(right.AsRegisterPairLow<Register>()),
1821 EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001822 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001823 break;
1824 case kCondLE:
1825 case kCondGT:
1826 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001827 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001828 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001829 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001830 } else {
1831 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001832 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001833 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001834 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001835 }
1836
1837 std::swap(left, right);
1838 FALLTHROUGH_INTENDED;
1839 case kCondGE:
1840 case kCondLT:
1841 __ cmp(left.AsRegisterPairLow<Register>(),
1842 ShifterOperand(right.AsRegisterPairLow<Register>()));
1843 __ sbcs(IP,
1844 left.AsRegisterPairHigh<Register>(),
1845 ShifterOperand(right.AsRegisterPairHigh<Register>()));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001846 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001847 break;
1848 default:
1849 LOG(FATAL) << "Unreachable";
1850 UNREACHABLE();
1851 }
1852
1853 return ret;
1854}
1855
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001856static std::pair<Condition, Condition> GenerateTest(HCondition* condition,
1857 bool invert,
1858 CodeGeneratorARM* codegen) {
1859 const LocationSummary* const locations = condition->GetLocations();
1860 const Primitive::Type type = condition->GetLeft()->GetType();
1861 IfCondition cond = condition->GetCondition();
1862 IfCondition opposite = condition->GetOppositeCondition();
1863 std::pair<Condition, Condition> ret;
1864 const Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08001865
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001866 if (invert) {
1867 std::swap(cond, opposite);
1868 }
Donghui Bai426b49c2016-11-08 14:55:38 +08001869
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001870 if (type == Primitive::kPrimLong) {
1871 ret = locations->InAt(1).IsConstant()
1872 ? GenerateLongTestConstant(condition, invert, codegen)
1873 : GenerateLongTest(condition, invert, codegen);
1874 } else if (Primitive::IsFloatingPointType(type)) {
1875 GenerateVcmp(condition, codegen);
1876 __ vmstat();
1877 ret = std::make_pair(ARMFPCondition(cond, condition->IsGtBias()),
1878 ARMFPCondition(opposite, condition->IsGtBias()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001879 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001880 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
Donghui Bai426b49c2016-11-08 14:55:38 +08001881
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001882 const Register left = locations->InAt(0).AsRegister<Register>();
1883
1884 if (right.IsRegister()) {
1885 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001886 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001887 DCHECK(right.IsConstant());
1888 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001889 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001890
1891 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001892 }
1893
1894 return ret;
1895}
1896
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001897static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) {
1898 if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
1899 const LocationSummary* const locations = condition->GetLocations();
Donghui Bai426b49c2016-11-08 14:55:38 +08001900
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001901 if (locations->InAt(1).IsConstant()) {
Anton Kirilov5601d4e2017-05-11 19:33:50 +01001902 IfCondition c = condition->GetCondition();
1903 IfCondition opposite = condition->GetOppositeCondition();
1904 const int64_t value = AdjustConstantForCondition(
1905 Int64FromConstant(locations->InAt(1).GetConstant()),
1906 &c,
1907 &opposite);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001908 ShifterOperand so;
Donghui Bai426b49c2016-11-08 14:55:38 +08001909
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001910 if (c < kCondLT || c > kCondGE) {
1911 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1912 // we check that the least significant half of the first input to be compared
1913 // is in a low register (the other half is read outside an IT block), and
1914 // the constant fits in an 8-bit unsigned integer, so that a 16-bit CMP
Anton Kirilov5601d4e2017-05-11 19:33:50 +01001915 // encoding can be used; 0 is always handled, no matter what registers are
1916 // used by the first input.
1917 if (value != 0 &&
1918 (!ArmAssembler::IsLowRegister(locations->InAt(0).AsRegisterPairLow<Register>()) ||
1919 !IsUint<8>(Low32Bits(value)))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001920 return false;
1921 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001922 } else if (c == kCondLE || c == kCondGT) {
1923 if (value < std::numeric_limits<int64_t>::max() &&
1924 !assembler->ShifterOperandCanHold(kNoRegister,
1925 kNoRegister,
1926 SBC,
1927 High32Bits(value + 1),
1928 kCcSet,
1929 &so)) {
1930 return false;
1931 }
1932 } else if (!assembler->ShifterOperandCanHold(kNoRegister,
1933 kNoRegister,
1934 SBC,
1935 High32Bits(value),
1936 kCcSet,
1937 &so)) {
1938 return false;
Donghui Bai426b49c2016-11-08 14:55:38 +08001939 }
1940 }
1941 }
1942
1943 return true;
1944}
1945
Anton Kirilov5601d4e2017-05-11 19:33:50 +01001946static void GenerateConditionGeneric(HCondition* cond, CodeGeneratorARM* codegen) {
1947 DCHECK(CanGenerateTest(cond, codegen->GetAssembler()));
1948
1949 const Register out = cond->GetLocations()->Out().AsRegister<Register>();
1950 const auto condition = GenerateTest(cond, false, codegen);
1951
1952 __ mov(out, ShifterOperand(0), AL, kCcKeep);
1953
1954 if (ArmAssembler::IsLowRegister(out)) {
1955 __ it(condition.first);
1956 __ mov(out, ShifterOperand(1), condition.first);
1957 } else {
1958 Label done_label;
1959 Label* const final_label = codegen->GetFinalLabel(cond, &done_label);
1960
1961 __ b(final_label, condition.second);
1962 __ LoadImmediate(out, 1);
1963
1964 if (done_label.IsLinked()) {
1965 __ Bind(&done_label);
1966 }
1967 }
1968}
1969
1970static void GenerateEqualLong(HCondition* cond, CodeGeneratorARM* codegen) {
1971 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
1972
1973 const LocationSummary* const locations = cond->GetLocations();
1974 IfCondition condition = cond->GetCondition();
1975 const Register out = locations->Out().AsRegister<Register>();
1976 const Location left = locations->InAt(0);
1977 const Location right = locations->InAt(1);
1978 Register left_high = left.AsRegisterPairHigh<Register>();
1979 Register left_low = left.AsRegisterPairLow<Register>();
1980
1981 if (right.IsConstant()) {
1982 IfCondition opposite = cond->GetOppositeCondition();
1983 const int64_t value = AdjustConstantForCondition(Int64FromConstant(right.GetConstant()),
1984 &condition,
1985 &opposite);
1986 int32_t value_high = -High32Bits(value);
1987 int32_t value_low = -Low32Bits(value);
1988
1989 // The output uses Location::kNoOutputOverlap.
1990 if (out == left_high) {
1991 std::swap(left_low, left_high);
1992 std::swap(value_low, value_high);
1993 }
1994
1995 __ AddConstant(out, left_low, value_low);
1996 __ AddConstant(IP, left_high, value_high);
1997 } else {
1998 DCHECK(right.IsRegisterPair());
1999 __ sub(IP, left_high, ShifterOperand(right.AsRegisterPairHigh<Register>()));
2000 __ sub(out, left_low, ShifterOperand(right.AsRegisterPairLow<Register>()));
2001 }
2002
2003 // Need to check after calling AdjustConstantForCondition().
2004 DCHECK(condition == kCondEQ || condition == kCondNE) << condition;
2005
2006 if (condition == kCondNE && ArmAssembler::IsLowRegister(out)) {
2007 __ orrs(out, out, ShifterOperand(IP));
2008 __ it(NE);
2009 __ mov(out, ShifterOperand(1), NE);
2010 } else {
2011 __ orr(out, out, ShifterOperand(IP));
2012 codegen->GenerateConditionWithZero(condition, out, out, IP);
2013 }
2014}
2015
2016static void GenerateLongComparesAndJumps(HCondition* cond,
2017 Label* true_label,
2018 Label* false_label,
2019 CodeGeneratorARM* codegen) {
2020 LocationSummary* locations = cond->GetLocations();
2021 Location left = locations->InAt(0);
2022 Location right = locations->InAt(1);
2023 IfCondition if_cond = cond->GetCondition();
2024
2025 Register left_high = left.AsRegisterPairHigh<Register>();
2026 Register left_low = left.AsRegisterPairLow<Register>();
2027 IfCondition true_high_cond = if_cond;
2028 IfCondition false_high_cond = cond->GetOppositeCondition();
2029 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
2030
2031 // Set the conditions for the test, remembering that == needs to be
2032 // decided using the low words.
2033 switch (if_cond) {
2034 case kCondEQ:
2035 case kCondNE:
2036 // Nothing to do.
2037 break;
2038 case kCondLT:
2039 false_high_cond = kCondGT;
2040 break;
2041 case kCondLE:
2042 true_high_cond = kCondLT;
2043 break;
2044 case kCondGT:
2045 false_high_cond = kCondLT;
2046 break;
2047 case kCondGE:
2048 true_high_cond = kCondGT;
2049 break;
2050 case kCondB:
2051 false_high_cond = kCondA;
2052 break;
2053 case kCondBE:
2054 true_high_cond = kCondB;
2055 break;
2056 case kCondA:
2057 false_high_cond = kCondB;
2058 break;
2059 case kCondAE:
2060 true_high_cond = kCondA;
2061 break;
2062 }
2063 if (right.IsConstant()) {
2064 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
2065 int32_t val_low = Low32Bits(value);
2066 int32_t val_high = High32Bits(value);
2067
2068 __ CmpConstant(left_high, val_high);
2069 if (if_cond == kCondNE) {
2070 __ b(true_label, ARMCondition(true_high_cond));
2071 } else if (if_cond == kCondEQ) {
2072 __ b(false_label, ARMCondition(false_high_cond));
2073 } else {
2074 __ b(true_label, ARMCondition(true_high_cond));
2075 __ b(false_label, ARMCondition(false_high_cond));
2076 }
2077 // Must be equal high, so compare the lows.
2078 __ CmpConstant(left_low, val_low);
2079 } else {
2080 Register right_high = right.AsRegisterPairHigh<Register>();
2081 Register right_low = right.AsRegisterPairLow<Register>();
2082
2083 __ cmp(left_high, ShifterOperand(right_high));
2084 if (if_cond == kCondNE) {
2085 __ b(true_label, ARMCondition(true_high_cond));
2086 } else if (if_cond == kCondEQ) {
2087 __ b(false_label, ARMCondition(false_high_cond));
2088 } else {
2089 __ b(true_label, ARMCondition(true_high_cond));
2090 __ b(false_label, ARMCondition(false_high_cond));
2091 }
2092 // Must be equal high, so compare the lows.
2093 __ cmp(left_low, ShifterOperand(right_low));
2094 }
2095 // The last comparison might be unsigned.
2096 // TODO: optimize cases where this is always true/false
2097 __ b(true_label, final_condition);
2098}
2099
2100static void GenerateConditionLong(HCondition* cond, CodeGeneratorARM* codegen) {
2101 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
2102
2103 const LocationSummary* const locations = cond->GetLocations();
2104 IfCondition condition = cond->GetCondition();
2105 const Register out = locations->Out().AsRegister<Register>();
2106 const Location left = locations->InAt(0);
2107 const Location right = locations->InAt(1);
2108
2109 if (right.IsConstant()) {
2110 IfCondition opposite = cond->GetOppositeCondition();
2111
2112 // Comparisons against 0 are common enough to deserve special attention.
2113 if (AdjustConstantForCondition(Int64FromConstant(right.GetConstant()),
2114 &condition,
2115 &opposite) == 0) {
2116 switch (condition) {
2117 case kCondNE:
2118 case kCondA:
2119 if (ArmAssembler::IsLowRegister(out)) {
2120 // We only care if both input registers are 0 or not.
2121 __ orrs(out,
2122 left.AsRegisterPairLow<Register>(),
2123 ShifterOperand(left.AsRegisterPairHigh<Register>()));
2124 __ it(NE);
2125 __ mov(out, ShifterOperand(1), NE);
2126 return;
2127 }
2128
2129 FALLTHROUGH_INTENDED;
2130 case kCondEQ:
2131 case kCondBE:
2132 // We only care if both input registers are 0 or not.
2133 __ orr(out,
2134 left.AsRegisterPairLow<Register>(),
2135 ShifterOperand(left.AsRegisterPairHigh<Register>()));
2136 codegen->GenerateConditionWithZero(condition, out, out);
2137 return;
2138 case kCondLT:
2139 case kCondGE:
2140 // We only care about the sign bit.
2141 FALLTHROUGH_INTENDED;
2142 case kCondAE:
2143 case kCondB:
2144 codegen->GenerateConditionWithZero(condition, out, left.AsRegisterPairHigh<Register>());
2145 return;
2146 case kCondLE:
2147 case kCondGT:
2148 default:
2149 break;
2150 }
2151 }
2152 }
2153
2154 if ((condition == kCondEQ || condition == kCondNE) &&
2155 // If `out` is a low register, then the GenerateConditionGeneric()
2156 // function generates a shorter code sequence that is still branchless.
2157 (!ArmAssembler::IsLowRegister(out) || !CanGenerateTest(cond, codegen->GetAssembler()))) {
2158 GenerateEqualLong(cond, codegen);
2159 return;
2160 }
2161
2162 if (CanGenerateTest(cond, codegen->GetAssembler())) {
2163 GenerateConditionGeneric(cond, codegen);
2164 return;
2165 }
2166
2167 // Convert the jumps into the result.
2168 Label done_label;
2169 Label* const final_label = codegen->GetFinalLabel(cond, &done_label);
2170 Label true_label, false_label;
2171
2172 GenerateLongComparesAndJumps(cond, &true_label, &false_label, codegen);
2173
2174 // False case: result = 0.
2175 __ Bind(&false_label);
2176 __ mov(out, ShifterOperand(0));
2177 __ b(final_label);
2178
2179 // True case: result = 1.
2180 __ Bind(&true_label);
2181 __ mov(out, ShifterOperand(1));
2182
2183 if (done_label.IsLinked()) {
2184 __ Bind(&done_label);
2185 }
2186}
2187
2188static void GenerateConditionIntegralOrNonPrimitive(HCondition* cond, CodeGeneratorARM* codegen) {
2189 const Primitive::Type type = cond->GetLeft()->GetType();
2190
2191 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
2192
2193 if (type == Primitive::kPrimLong) {
2194 GenerateConditionLong(cond, codegen);
2195 return;
2196 }
2197
2198 const LocationSummary* const locations = cond->GetLocations();
2199 IfCondition condition = cond->GetCondition();
2200 Register in = locations->InAt(0).AsRegister<Register>();
2201 const Register out = locations->Out().AsRegister<Register>();
2202 const Location right = cond->GetLocations()->InAt(1);
2203 int64_t value;
2204
2205 if (right.IsConstant()) {
2206 IfCondition opposite = cond->GetOppositeCondition();
2207
2208 value = AdjustConstantForCondition(Int64FromConstant(right.GetConstant()),
2209 &condition,
2210 &opposite);
2211
2212 // Comparisons against 0 are common enough to deserve special attention.
2213 if (value == 0) {
2214 switch (condition) {
2215 case kCondNE:
2216 case kCondA:
2217 if (ArmAssembler::IsLowRegister(out) && out == in) {
2218 __ cmp(out, ShifterOperand(0));
2219 __ it(NE);
2220 __ mov(out, ShifterOperand(1), NE);
2221 return;
2222 }
2223
2224 FALLTHROUGH_INTENDED;
2225 case kCondEQ:
2226 case kCondBE:
2227 case kCondLT:
2228 case kCondGE:
2229 case kCondAE:
2230 case kCondB:
2231 codegen->GenerateConditionWithZero(condition, out, in);
2232 return;
2233 case kCondLE:
2234 case kCondGT:
2235 default:
2236 break;
2237 }
2238 }
2239 }
2240
2241 if (condition == kCondEQ || condition == kCondNE) {
2242 ShifterOperand operand;
2243
2244 if (right.IsConstant()) {
2245 operand = ShifterOperand(value);
2246 } else if (out == right.AsRegister<Register>()) {
2247 // Avoid 32-bit instructions if possible.
2248 operand = ShifterOperand(in);
2249 in = right.AsRegister<Register>();
2250 } else {
2251 operand = ShifterOperand(right.AsRegister<Register>());
2252 }
2253
2254 if (condition == kCondNE && ArmAssembler::IsLowRegister(out)) {
2255 __ subs(out, in, operand);
2256 __ it(NE);
2257 __ mov(out, ShifterOperand(1), NE);
2258 } else {
2259 __ sub(out, in, operand);
2260 codegen->GenerateConditionWithZero(condition, out, out);
2261 }
2262
2263 return;
2264 }
2265
2266 GenerateConditionGeneric(cond, codegen);
2267}
2268
Donghui Bai426b49c2016-11-08 14:55:38 +08002269static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) {
2270 const Primitive::Type type = constant->GetType();
2271 bool ret = false;
2272
2273 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
2274
2275 if (type == Primitive::kPrimLong) {
2276 const uint64_t value = constant->AsLongConstant()->GetValueAsUint64();
2277
2278 ret = IsUint<8>(Low32Bits(value)) && IsUint<8>(High32Bits(value));
2279 } else {
2280 ret = IsUint<8>(CodeGenerator::GetInt32ValueOf(constant));
2281 }
2282
2283 return ret;
2284}
2285
2286static Location Arm8BitEncodableConstantOrRegister(HInstruction* constant) {
2287 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
2288
2289 if (constant->IsConstant() && CanEncodeConstantAs8BitImmediate(constant->AsConstant())) {
2290 return Location::ConstantLocation(constant->AsConstant());
2291 }
2292
2293 return Location::RequiresRegister();
2294}
2295
2296static bool CanGenerateConditionalMove(const Location& out, const Location& src) {
2297 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
2298 // we check that we are not dealing with floating-point output (there is no
2299 // 16-bit VMOV encoding).
2300 if (!out.IsRegister() && !out.IsRegisterPair()) {
2301 return false;
2302 }
2303
2304 // For constants, we also check that the output is in one or two low registers,
2305 // and that the constants fit in an 8-bit unsigned integer, so that a 16-bit
2306 // MOV encoding can be used.
2307 if (src.IsConstant()) {
2308 if (!CanEncodeConstantAs8BitImmediate(src.GetConstant())) {
2309 return false;
2310 }
2311
2312 if (out.IsRegister()) {
2313 if (!ArmAssembler::IsLowRegister(out.AsRegister<Register>())) {
2314 return false;
2315 }
2316 } else {
2317 DCHECK(out.IsRegisterPair());
2318
2319 if (!ArmAssembler::IsLowRegister(out.AsRegisterPairHigh<Register>())) {
2320 return false;
2321 }
2322 }
2323 }
2324
2325 return true;
2326}
2327
Anton Kirilov74234da2017-01-13 14:42:47 +00002328#undef __
2329// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
2330#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
2331
Donghui Bai426b49c2016-11-08 14:55:38 +08002332Label* CodeGeneratorARM::GetFinalLabel(HInstruction* instruction, Label* final_label) {
2333 DCHECK(!instruction->IsControlFlow() && !instruction->IsSuspendCheck());
Anton Kirilov6f644202017-02-27 18:29:45 +00002334 DCHECK(!instruction->IsInvoke() || !instruction->GetLocations()->CanCall());
Donghui Bai426b49c2016-11-08 14:55:38 +08002335
2336 const HBasicBlock* const block = instruction->GetBlock();
2337 const HLoopInformation* const info = block->GetLoopInformation();
2338 HInstruction* const next = instruction->GetNext();
2339
2340 // Avoid a branch to a branch.
2341 if (next->IsGoto() && (info == nullptr ||
2342 !info->IsBackEdge(*block) ||
2343 !info->HasSuspendCheck())) {
2344 final_label = GetLabelOf(next->AsGoto()->GetSuccessor());
2345 }
2346
2347 return final_label;
2348}
2349
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01002350void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01002351 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01002352}
2353
2354void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01002355 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01002356}
2357
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002358size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
2359 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
2360 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01002361}
2362
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002363size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
2364 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
2365 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01002366}
2367
Nicolas Geoffray840e5462015-01-07 16:01:24 +00002368size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
2369 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
2370 return kArmWordSize;
2371}
2372
2373size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
2374 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
2375 return kArmWordSize;
2376}
2377
Calin Juravle34166012014-12-19 17:22:29 +00002378CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002379 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +01002380 const CompilerOptions& compiler_options,
2381 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002382 : CodeGenerator(graph,
2383 kNumberOfCoreRegisters,
2384 kNumberOfSRegisters,
2385 kNumberOfRegisterPairs,
2386 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
2387 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +00002388 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
2389 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01002390 compiler_options,
2391 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01002392 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002393 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002394 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002395 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +01002396 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +00002397 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00002398 uint32_literals_(std::less<uint32_t>(),
2399 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko65979462017-05-19 17:25:12 +01002400 pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko0eb882b2017-05-15 13:39:18 +01002401 method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01002402 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +00002403 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko65979462017-05-19 17:25:12 +01002404 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01002405 baker_read_barrier_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray132d8362016-11-16 09:19:42 +00002406 jit_string_patches_(StringReferenceValueComparator(),
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00002407 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2408 jit_class_patches_(TypeReferenceValueComparator(),
2409 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -07002410 // Always save the LR register to mimic Quick.
2411 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +01002412}
2413
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002414void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
2415 // Ensure that we fix up branches and literal loads and emit the literal pool.
2416 __ FinalizeCode();
2417
2418 // Adjust native pc offsets in stack maps.
2419 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08002420 uint32_t old_position =
2421 stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kThumb2);
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002422 uint32_t new_position = __ GetAdjustedPosition(old_position);
2423 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
2424 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +01002425 // Adjust pc offsets for the disassembly information.
2426 if (disasm_info_ != nullptr) {
2427 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
2428 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
2429 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
2430 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
2431 it.second.start = __ GetAdjustedPosition(it.second.start);
2432 it.second.end = __ GetAdjustedPosition(it.second.end);
2433 }
2434 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
2435 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
2436 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
2437 }
2438 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002439
2440 CodeGenerator::Finalize(allocator);
2441}
2442
David Brazdil58282f42016-01-14 12:45:10 +00002443void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002444 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002445 blocked_core_registers_[SP] = true;
2446 blocked_core_registers_[LR] = true;
2447 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002448
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002449 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002450 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002451
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002452 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002453 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002454
David Brazdil58282f42016-01-14 12:45:10 +00002455 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +01002456 // Stubs do not save callee-save floating point registers. If the graph
2457 // is debuggable, we need to deal with these registers differently. For
2458 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002459 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
2460 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
2461 }
2462 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002463}
2464
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002465InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08002466 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002467 assembler_(codegen->GetAssembler()),
2468 codegen_(codegen) {}
2469
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002470void CodeGeneratorARM::ComputeSpillMask() {
2471 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
2472 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +00002473 // There is no easy instruction to restore just the PC on thumb2. We spill and
2474 // restore another arbitrary register.
2475 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002476 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
2477 // We use vpush and vpop for saving and restoring floating point registers, which take
2478 // a SRegister and the number of registers to save/restore after that SRegister. We
2479 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
2480 // but in the range.
2481 if (fpu_spill_mask_ != 0) {
2482 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
2483 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
2484 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
2485 fpu_spill_mask_ |= (1 << i);
2486 }
2487 }
2488}
2489
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002490static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002491 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002492}
2493
2494static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002495 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002496}
2497
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002498void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +00002499 bool skip_overflow_check =
2500 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002501 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00002502 __ Bind(&frame_entry_label_);
2503
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002504 if (HasEmptyFrame()) {
2505 return;
2506 }
2507
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002508 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002509 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
2510 __ LoadFromOffset(kLoadWord, IP, IP, 0);
2511 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002512 }
2513
Andreas Gampe501fd632015-09-10 16:11:06 -07002514 __ PushList(core_spill_mask_);
2515 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
2516 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002517 if (fpu_spill_mask_ != 0) {
2518 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2519 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002520 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +01002521 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002522 }
Mingyao Yang063fc772016-08-02 11:02:54 -07002523
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002524 int adjust = GetFrameSize() - FrameEntrySpillSize();
2525 __ AddConstant(SP, -adjust);
2526 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01002527
2528 // Save the current method if we need it. Note that we do not
2529 // do this in HCurrentMethod, as the instruction might have been removed
2530 // in the SSA graph.
2531 if (RequiresCurrentMethod()) {
2532 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
2533 }
Nicolas Geoffrayf7893532017-06-15 12:34:36 +01002534
2535 if (GetGraph()->HasShouldDeoptimizeFlag()) {
2536 // Initialize should_deoptimize flag to 0.
2537 __ mov(IP, ShifterOperand(0));
2538 __ StoreToOffset(kStoreWord, IP, SP, GetStackOffsetOfShouldDeoptimizeFlag());
2539 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002540}
2541
2542void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002543 if (HasEmptyFrame()) {
2544 __ bx(LR);
2545 return;
2546 }
David Srbeckyc34dc932015-04-12 09:27:43 +01002547 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002548 int adjust = GetFrameSize() - FrameEntrySpillSize();
2549 __ AddConstant(SP, adjust);
2550 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002551 if (fpu_spill_mask_ != 0) {
2552 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2553 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
Andreas Gampe542451c2016-07-26 09:02:02 -07002554 __ cfi().AdjustCFAOffset(-static_cast<int>(kArmPointerSize) * POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002555 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002556 }
Andreas Gampe501fd632015-09-10 16:11:06 -07002557 // Pop LR into PC to return.
2558 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
2559 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
2560 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +01002561 __ cfi().RestoreState();
2562 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002563}
2564
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002565void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07002566 Label* label = GetLabelOf(block);
2567 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002568}
2569
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002570Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002571 switch (type) {
2572 case Primitive::kPrimBoolean:
2573 case Primitive::kPrimByte:
2574 case Primitive::kPrimChar:
2575 case Primitive::kPrimShort:
2576 case Primitive::kPrimInt:
2577 case Primitive::kPrimNot: {
2578 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002579 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002580 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002581 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002582 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002583 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002584 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002585 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002586
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002587 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002588 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002589 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002590 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002591 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002592 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002593 if (calling_convention.GetRegisterAt(index) == R1) {
2594 // Skip R1, and use R2_R3 instead.
2595 gp_index_++;
2596 index++;
2597 }
2598 }
2599 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
2600 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002601 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01002602
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002603 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002604 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002605 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002606 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
2607 }
2608 }
2609
2610 case Primitive::kPrimFloat: {
2611 uint32_t stack_index = stack_index_++;
2612 if (float_index_ % 2 == 0) {
2613 float_index_ = std::max(double_index_, float_index_);
2614 }
2615 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
2616 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
2617 } else {
2618 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
2619 }
2620 }
2621
2622 case Primitive::kPrimDouble: {
2623 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
2624 uint32_t stack_index = stack_index_;
2625 stack_index_ += 2;
2626 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
2627 uint32_t index = double_index_;
2628 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002629 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002630 calling_convention.GetFpuRegisterAt(index),
2631 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002632 DCHECK(ExpectedPairLayout(result));
2633 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002634 } else {
2635 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002636 }
2637 }
2638
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002639 case Primitive::kPrimVoid:
2640 LOG(FATAL) << "Unexpected parameter type " << type;
2641 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002642 }
Roland Levillain3b359c72015-11-17 19:35:12 +00002643 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002644}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002645
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002646Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002647 switch (type) {
2648 case Primitive::kPrimBoolean:
2649 case Primitive::kPrimByte:
2650 case Primitive::kPrimChar:
2651 case Primitive::kPrimShort:
2652 case Primitive::kPrimInt:
2653 case Primitive::kPrimNot: {
2654 return Location::RegisterLocation(R0);
2655 }
2656
2657 case Primitive::kPrimFloat: {
2658 return Location::FpuRegisterLocation(S0);
2659 }
2660
2661 case Primitive::kPrimLong: {
2662 return Location::RegisterPairLocation(R0, R1);
2663 }
2664
2665 case Primitive::kPrimDouble: {
2666 return Location::FpuRegisterPairLocation(S0, S1);
2667 }
2668
2669 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00002670 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002671 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002672
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002673 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002674}
2675
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002676Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
2677 return Location::RegisterLocation(kMethodRegisterArgument);
2678}
2679
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002680void CodeGeneratorARM::Move32(Location destination, Location source) {
2681 if (source.Equals(destination)) {
2682 return;
2683 }
2684 if (destination.IsRegister()) {
2685 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002686 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002687 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002688 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002689 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002690 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002691 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002692 } else if (destination.IsFpuRegister()) {
2693 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002694 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002695 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002696 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002697 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002698 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002699 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002700 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002701 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002702 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002703 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002704 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002705 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002706 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002707 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002708 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
2709 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002710 }
2711 }
2712}
2713
2714void CodeGeneratorARM::Move64(Location destination, Location source) {
2715 if (source.Equals(destination)) {
2716 return;
2717 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002718 if (destination.IsRegisterPair()) {
2719 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002720 EmitParallelMoves(
2721 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
2722 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002723 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002724 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002725 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
2726 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002727 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002728 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002729 } else if (source.IsFpuRegisterPair()) {
2730 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
2731 destination.AsRegisterPairHigh<Register>(),
2732 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002733 } else {
2734 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002735 DCHECK(ExpectedPairLayout(destination));
2736 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
2737 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002738 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002739 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002740 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002741 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2742 SP,
2743 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01002744 } else if (source.IsRegisterPair()) {
2745 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2746 source.AsRegisterPairLow<Register>(),
2747 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002748 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002749 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002750 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002751 } else {
2752 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002753 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002754 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002755 if (source.AsRegisterPairLow<Register>() == R1) {
2756 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002757 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
2758 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002759 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002760 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002761 SP, destination.GetStackIndex());
2762 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002763 } else if (source.IsFpuRegisterPair()) {
2764 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
2765 SP,
2766 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002767 } else {
2768 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002769 EmitParallelMoves(
2770 Location::StackSlot(source.GetStackIndex()),
2771 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002772 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002773 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002774 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
2775 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002776 }
2777 }
2778}
2779
Calin Juravle175dc732015-08-25 15:42:32 +01002780void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
2781 DCHECK(location.IsRegister());
2782 __ LoadImmediate(location.AsRegister<Register>(), value);
2783}
2784
Calin Juravlee460d1d2015-09-29 04:52:17 +01002785void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00002786 HParallelMove move(GetGraph()->GetArena());
2787 move.AddMove(src, dst, dst_type, nullptr);
2788 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002789}
2790
2791void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
2792 if (location.IsRegister()) {
2793 locations->AddTemp(location);
2794 } else if (location.IsRegisterPair()) {
2795 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
2796 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
2797 } else {
2798 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
2799 }
2800}
2801
Calin Juravle175dc732015-08-25 15:42:32 +01002802void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
2803 HInstruction* instruction,
2804 uint32_t dex_pc,
2805 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01002806 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002807 GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
Serban Constantinescuda8ffec2016-03-09 12:02:11 +00002808 if (EntrypointRequiresStackMap(entrypoint)) {
2809 RecordPcInfo(instruction, dex_pc, slow_path);
2810 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002811}
2812
Roland Levillaindec8f632016-07-22 17:10:06 +01002813void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
2814 HInstruction* instruction,
2815 SlowPathCode* slow_path) {
2816 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002817 GenerateInvokeRuntime(entry_point_offset);
2818}
2819
2820void CodeGeneratorARM::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01002821 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
2822 __ blx(LR);
2823}
2824
David Brazdilfc6a86a2015-06-26 10:33:45 +00002825void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002826 DCHECK(!successor->IsExitBlock());
2827
2828 HBasicBlock* block = got->GetBlock();
2829 HInstruction* previous = got->GetPrevious();
2830
2831 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00002832 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002833 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2834 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2835 return;
2836 }
2837
2838 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2839 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2840 }
2841 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002842 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002843 }
2844}
2845
David Brazdilfc6a86a2015-06-26 10:33:45 +00002846void LocationsBuilderARM::VisitGoto(HGoto* got) {
2847 got->SetLocations(nullptr);
2848}
2849
2850void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
2851 HandleGoto(got, got->GetSuccessor());
2852}
2853
2854void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2855 try_boundary->SetLocations(nullptr);
2856}
2857
2858void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2859 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2860 if (!successor->IsExitBlock()) {
2861 HandleGoto(try_boundary, successor);
2862 }
2863}
2864
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002865void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002866 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002867}
2868
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002869void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002870}
2871
David Brazdil0debae72015-11-12 18:37:00 +00002872void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
2873 Label* true_target_in,
2874 Label* false_target_in) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002875 if (CanGenerateTest(condition, codegen_->GetAssembler())) {
2876 Label* non_fallthrough_target;
2877 bool invert;
Nicolas Geoffray6fda4272017-06-26 09:12:45 +01002878 bool emit_both_branches;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002879
2880 if (true_target_in == nullptr) {
Nicolas Geoffray6fda4272017-06-26 09:12:45 +01002881 // The true target is fallthrough.
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002882 DCHECK(false_target_in != nullptr);
2883 non_fallthrough_target = false_target_in;
2884 invert = true;
Nicolas Geoffray6fda4272017-06-26 09:12:45 +01002885 emit_both_branches = false;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002886 } else {
Nicolas Geoffray6fda4272017-06-26 09:12:45 +01002887 // Either the false target is fallthrough, or there is no fallthrough
2888 // and both branches must be emitted.
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002889 non_fallthrough_target = true_target_in;
2890 invert = false;
Nicolas Geoffray6fda4272017-06-26 09:12:45 +01002891 emit_both_branches = (false_target_in != nullptr);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002892 }
2893
2894 const auto cond = GenerateTest(condition, invert, codegen_);
2895
2896 __ b(non_fallthrough_target, cond.first);
2897
Nicolas Geoffray6fda4272017-06-26 09:12:45 +01002898 if (emit_both_branches) {
2899 // No target falls through, we need to branch.
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002900 __ b(false_target_in);
2901 }
2902
2903 return;
2904 }
2905
David Brazdil0debae72015-11-12 18:37:00 +00002906 // Generated branching requires both targets to be explicit. If either of the
2907 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
2908 Label fallthrough_target;
2909 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
2910 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
2911
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002912 DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
Anton Kirilov5601d4e2017-05-11 19:33:50 +01002913 GenerateLongComparesAndJumps(condition, true_target, false_target, codegen_);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002914
David Brazdil0debae72015-11-12 18:37:00 +00002915 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002916 __ b(false_target);
2917 }
David Brazdil0debae72015-11-12 18:37:00 +00002918
2919 if (fallthrough_target.IsLinked()) {
2920 __ Bind(&fallthrough_target);
2921 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01002922}
2923
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002924void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00002925 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002926 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00002927 Label* false_target) {
2928 HInstruction* cond = instruction->InputAt(condition_input_index);
2929
2930 if (true_target == nullptr && false_target == nullptr) {
2931 // Nothing to do. The code always falls through.
2932 return;
2933 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00002934 // Constant condition, statically compared against "true" (integer value 1).
2935 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00002936 if (true_target != nullptr) {
2937 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002938 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002939 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00002940 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00002941 if (false_target != nullptr) {
2942 __ b(false_target);
2943 }
2944 }
2945 return;
2946 }
2947
2948 // The following code generates these patterns:
2949 // (1) true_target == nullptr && false_target != nullptr
2950 // - opposite condition true => branch to false_target
2951 // (2) true_target != nullptr && false_target == nullptr
2952 // - condition true => branch to true_target
2953 // (3) true_target != nullptr && false_target != nullptr
2954 // - condition true => branch to true_target
2955 // - branch to false_target
2956 if (IsBooleanValueOrMaterializedCondition(cond)) {
2957 // Condition has been materialized, compare the output to 0.
2958 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
2959 DCHECK(cond_val.IsRegister());
2960 if (true_target == nullptr) {
2961 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
2962 } else {
2963 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002964 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002965 } else {
David Brazdil0debae72015-11-12 18:37:00 +00002966 // Condition has not been materialized. Use its inputs as the comparison and
2967 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04002968 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00002969
2970 // If this is a long or FP comparison that has been folded into
2971 // the HCondition, generate the comparison directly.
2972 Primitive::Type type = condition->InputAt(0)->GetType();
2973 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
2974 GenerateCompareTestAndBranch(condition, true_target, false_target);
2975 return;
2976 }
2977
Donghui Bai426b49c2016-11-08 14:55:38 +08002978 Label* non_fallthrough_target;
2979 Condition arm_cond;
David Brazdil0debae72015-11-12 18:37:00 +00002980 LocationSummary* locations = cond->GetLocations();
2981 DCHECK(locations->InAt(0).IsRegister());
2982 Register left = locations->InAt(0).AsRegister<Register>();
2983 Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08002984
David Brazdil0debae72015-11-12 18:37:00 +00002985 if (true_target == nullptr) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002986 arm_cond = ARMCondition(condition->GetOppositeCondition());
2987 non_fallthrough_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00002988 } else {
Donghui Bai426b49c2016-11-08 14:55:38 +08002989 arm_cond = ARMCondition(condition->GetCondition());
2990 non_fallthrough_target = true_target;
2991 }
2992
2993 if (right.IsConstant() && (arm_cond == NE || arm_cond == EQ) &&
2994 CodeGenerator::GetInt32ValueOf(right.GetConstant()) == 0) {
2995 if (arm_cond == EQ) {
2996 __ CompareAndBranchIfZero(left, non_fallthrough_target);
2997 } else {
2998 DCHECK_EQ(arm_cond, NE);
2999 __ CompareAndBranchIfNonZero(left, non_fallthrough_target);
3000 }
3001 } else {
3002 if (right.IsRegister()) {
3003 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
3004 } else {
3005 DCHECK(right.IsConstant());
3006 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
3007 }
3008
3009 __ b(non_fallthrough_target, arm_cond);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01003010 }
Dave Allison20dfc792014-06-16 20:44:29 -07003011 }
David Brazdil0debae72015-11-12 18:37:00 +00003012
3013 // If neither branch falls through (case 3), the conditional branch to `true_target`
3014 // was already emitted (case 2) and we need to emit a jump to `false_target`.
3015 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07003016 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003017 }
3018}
3019
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07003020void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00003021 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
3022 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07003023 locations->SetInAt(0, Location::RequiresRegister());
3024 }
3025}
3026
3027void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00003028 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
3029 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
3030 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
3031 nullptr : codegen_->GetLabelOf(true_successor);
3032 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
3033 nullptr : codegen_->GetLabelOf(false_successor);
3034 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07003035}
3036
3037void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
3038 LocationSummary* locations = new (GetGraph()->GetArena())
3039 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01003040 InvokeRuntimeCallingConvention calling_convention;
3041 RegisterSet caller_saves = RegisterSet::Empty();
3042 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3043 locations->SetCustomSlowPathCallerSaves(caller_saves);
David Brazdil0debae72015-11-12 18:37:00 +00003044 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07003045 locations->SetInAt(0, Location::RequiresRegister());
3046 }
3047}
3048
3049void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01003050 SlowPathCodeARM* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00003051 GenerateTestAndBranch(deoptimize,
3052 /* condition_input_index */ 0,
3053 slow_path->GetEntryLabel(),
3054 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07003055}
Dave Allison20dfc792014-06-16 20:44:29 -07003056
Mingyao Yang063fc772016-08-02 11:02:54 -07003057void LocationsBuilderARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
3058 LocationSummary* locations = new (GetGraph()->GetArena())
3059 LocationSummary(flag, LocationSummary::kNoCall);
3060 locations->SetOut(Location::RequiresRegister());
3061}
3062
3063void InstructionCodeGeneratorARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
3064 __ LoadFromOffset(kLoadWord,
3065 flag->GetLocations()->Out().AsRegister<Register>(),
3066 SP,
3067 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
3068}
3069
David Brazdil74eb1b22015-12-14 11:44:01 +00003070void LocationsBuilderARM::VisitSelect(HSelect* select) {
3071 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
Donghui Bai426b49c2016-11-08 14:55:38 +08003072 const bool is_floating_point = Primitive::IsFloatingPointType(select->GetType());
3073
3074 if (is_floating_point) {
David Brazdil74eb1b22015-12-14 11:44:01 +00003075 locations->SetInAt(0, Location::RequiresFpuRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08003076 locations->SetInAt(1, Location::FpuRegisterOrConstant(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00003077 } else {
3078 locations->SetInAt(0, Location::RequiresRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08003079 locations->SetInAt(1, Arm8BitEncodableConstantOrRegister(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00003080 }
Donghui Bai426b49c2016-11-08 14:55:38 +08003081
David Brazdil74eb1b22015-12-14 11:44:01 +00003082 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
Donghui Bai426b49c2016-11-08 14:55:38 +08003083 locations->SetInAt(2, Location::RegisterOrConstant(select->GetCondition()));
3084 // The code generator handles overlap with the values, but not with the condition.
3085 locations->SetOut(Location::SameAsFirstInput());
3086 } else if (is_floating_point) {
3087 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3088 } else {
3089 if (!locations->InAt(1).IsConstant()) {
3090 locations->SetInAt(0, Arm8BitEncodableConstantOrRegister(select->GetFalseValue()));
3091 }
3092
3093 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
David Brazdil74eb1b22015-12-14 11:44:01 +00003094 }
David Brazdil74eb1b22015-12-14 11:44:01 +00003095}
3096
3097void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
Donghui Bai426b49c2016-11-08 14:55:38 +08003098 HInstruction* const condition = select->GetCondition();
3099 const LocationSummary* const locations = select->GetLocations();
3100 const Primitive::Type type = select->GetType();
3101 const Location first = locations->InAt(0);
3102 const Location out = locations->Out();
3103 const Location second = locations->InAt(1);
3104 Location src;
3105
3106 if (condition->IsIntConstant()) {
3107 if (condition->AsIntConstant()->IsFalse()) {
3108 src = first;
3109 } else {
3110 src = second;
3111 }
3112
3113 codegen_->MoveLocation(out, src, type);
3114 return;
3115 }
3116
3117 if (!Primitive::IsFloatingPointType(type) &&
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003118 (IsBooleanValueOrMaterializedCondition(condition) ||
3119 CanGenerateTest(condition->AsCondition(), codegen_->GetAssembler()))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08003120 bool invert = false;
3121
3122 if (out.Equals(second)) {
3123 src = first;
3124 invert = true;
3125 } else if (out.Equals(first)) {
3126 src = second;
3127 } else if (second.IsConstant()) {
3128 DCHECK(CanEncodeConstantAs8BitImmediate(second.GetConstant()));
3129 src = second;
3130 } else if (first.IsConstant()) {
3131 DCHECK(CanEncodeConstantAs8BitImmediate(first.GetConstant()));
3132 src = first;
3133 invert = true;
3134 } else {
3135 src = second;
3136 }
3137
3138 if (CanGenerateConditionalMove(out, src)) {
3139 if (!out.Equals(first) && !out.Equals(second)) {
3140 codegen_->MoveLocation(out, src.Equals(first) ? second : first, type);
3141 }
3142
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003143 std::pair<Condition, Condition> cond;
3144
3145 if (IsBooleanValueOrMaterializedCondition(condition)) {
3146 __ CmpConstant(locations->InAt(2).AsRegister<Register>(), 0);
3147 cond = invert ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
3148 } else {
3149 cond = GenerateTest(condition->AsCondition(), invert, codegen_);
3150 }
Donghui Bai426b49c2016-11-08 14:55:38 +08003151
3152 if (out.IsRegister()) {
3153 ShifterOperand operand;
3154
3155 if (src.IsConstant()) {
3156 operand = ShifterOperand(CodeGenerator::GetInt32ValueOf(src.GetConstant()));
3157 } else {
3158 DCHECK(src.IsRegister());
3159 operand = ShifterOperand(src.AsRegister<Register>());
3160 }
3161
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003162 __ it(cond.first);
3163 __ mov(out.AsRegister<Register>(), operand, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08003164 } else {
3165 DCHECK(out.IsRegisterPair());
3166
3167 ShifterOperand operand_high;
3168 ShifterOperand operand_low;
3169
3170 if (src.IsConstant()) {
3171 const int64_t value = src.GetConstant()->AsLongConstant()->GetValue();
3172
3173 operand_high = ShifterOperand(High32Bits(value));
3174 operand_low = ShifterOperand(Low32Bits(value));
3175 } else {
3176 DCHECK(src.IsRegisterPair());
3177 operand_high = ShifterOperand(src.AsRegisterPairHigh<Register>());
3178 operand_low = ShifterOperand(src.AsRegisterPairLow<Register>());
3179 }
3180
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003181 __ it(cond.first);
3182 __ mov(out.AsRegisterPairLow<Register>(), operand_low, cond.first);
3183 __ it(cond.first);
3184 __ mov(out.AsRegisterPairHigh<Register>(), operand_high, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08003185 }
3186
3187 return;
3188 }
3189 }
3190
3191 Label* false_target = nullptr;
3192 Label* true_target = nullptr;
3193 Label select_end;
3194 Label* target = codegen_->GetFinalLabel(select, &select_end);
3195
3196 if (out.Equals(second)) {
3197 true_target = target;
3198 src = first;
3199 } else {
3200 false_target = target;
3201 src = second;
3202
3203 if (!out.Equals(first)) {
3204 codegen_->MoveLocation(out, first, type);
3205 }
3206 }
3207
3208 GenerateTestAndBranch(select, 2, true_target, false_target);
3209 codegen_->MoveLocation(out, src, type);
3210
3211 if (select_end.IsLinked()) {
3212 __ Bind(&select_end);
3213 }
David Brazdil74eb1b22015-12-14 11:44:01 +00003214}
3215
David Srbecky0cf44932015-12-09 14:09:59 +00003216void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
3217 new (GetGraph()->GetArena()) LocationSummary(info);
3218}
3219
David Srbeckyd28f4a02016-03-14 17:14:24 +00003220void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
3221 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00003222}
3223
3224void CodeGeneratorARM::GenerateNop() {
3225 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00003226}
3227
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003228// `temp` is an extra temporary register that is used for some conditions;
3229// callers may not specify it, in which case the method will use a scratch
3230// register instead.
3231void CodeGeneratorARM::GenerateConditionWithZero(IfCondition condition,
3232 Register out,
3233 Register in,
3234 Register temp) {
3235 switch (condition) {
3236 case kCondEQ:
3237 // x <= 0 iff x == 0 when the comparison is unsigned.
3238 case kCondBE:
3239 if (temp == kNoRegister || (ArmAssembler::IsLowRegister(out) && out != in)) {
3240 temp = out;
3241 }
3242
3243 // Avoid 32-bit instructions if possible; note that `in` and `temp` must be
3244 // different as well.
3245 if (ArmAssembler::IsLowRegister(in) && ArmAssembler::IsLowRegister(temp) && in != temp) {
3246 // temp = - in; only 0 sets the carry flag.
3247 __ rsbs(temp, in, ShifterOperand(0));
3248
3249 if (out == in) {
3250 std::swap(in, temp);
3251 }
3252
3253 // out = - in + in + carry = carry
3254 __ adc(out, temp, ShifterOperand(in));
3255 } else {
3256 // If `in` is 0, then it has 32 leading zeros, and less than that otherwise.
3257 __ clz(out, in);
3258 // Any number less than 32 logically shifted right by 5 bits results in 0;
3259 // the same operation on 32 yields 1.
3260 __ Lsr(out, out, 5);
3261 }
3262
3263 break;
3264 case kCondNE:
3265 // x > 0 iff x != 0 when the comparison is unsigned.
3266 case kCondA:
3267 if (out == in) {
3268 if (temp == kNoRegister || in == temp) {
3269 temp = IP;
3270 }
3271 } else if (temp == kNoRegister || !ArmAssembler::IsLowRegister(temp)) {
3272 temp = out;
3273 }
3274
3275 // temp = in - 1; only 0 does not set the carry flag.
3276 __ subs(temp, in, ShifterOperand(1));
3277 // out = in + ~temp + carry = in + (-(in - 1) - 1) + carry = in - in + 1 - 1 + carry = carry
3278 __ sbc(out, in, ShifterOperand(temp));
3279 break;
3280 case kCondGE:
3281 __ mvn(out, ShifterOperand(in));
3282 in = out;
3283 FALLTHROUGH_INTENDED;
3284 case kCondLT:
3285 // We only care about the sign bit.
3286 __ Lsr(out, in, 31);
3287 break;
3288 case kCondAE:
3289 // Trivially true.
3290 __ mov(out, ShifterOperand(1));
3291 break;
3292 case kCondB:
3293 // Trivially false.
3294 __ mov(out, ShifterOperand(0));
3295 break;
3296 default:
3297 LOG(FATAL) << "Unexpected condition " << condition;
3298 UNREACHABLE();
3299 }
3300}
3301
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003302void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003303 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01003304 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003305 // Handle the long/FP comparisons made in instruction simplification.
3306 switch (cond->InputAt(0)->GetType()) {
3307 case Primitive::kPrimLong:
3308 locations->SetInAt(0, Location::RequiresRegister());
3309 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00003310 if (!cond->IsEmittedAtUseSite()) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003311 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003312 }
3313 break;
3314
3315 case Primitive::kPrimFloat:
3316 case Primitive::kPrimDouble:
3317 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01003318 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00003319 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01003320 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3321 }
3322 break;
3323
3324 default:
3325 locations->SetInAt(0, Location::RequiresRegister());
3326 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00003327 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01003328 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3329 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003330 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003331}
3332
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003333void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00003334 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01003335 return;
Dave Allison20dfc792014-06-16 20:44:29 -07003336 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01003337
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003338 const Primitive::Type type = cond->GetLeft()->GetType();
Roland Levillain4fa13f62015-07-06 18:11:54 +01003339
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003340 if (Primitive::IsFloatingPointType(type)) {
3341 GenerateConditionGeneric(cond, codegen_);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003342 return;
Roland Levillain4fa13f62015-07-06 18:11:54 +01003343 }
3344
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003345 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
Roland Levillain4fa13f62015-07-06 18:11:54 +01003346
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003347 const IfCondition condition = cond->GetCondition();
Roland Levillain4fa13f62015-07-06 18:11:54 +01003348
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003349 // A condition with only one boolean input, or two boolean inputs without being equality or
3350 // inequality results from transformations done by the instruction simplifier, and is handled
3351 // as a regular condition with integral inputs.
3352 if (type == Primitive::kPrimBoolean &&
3353 cond->GetRight()->GetType() == Primitive::kPrimBoolean &&
3354 (condition == kCondEQ || condition == kCondNE)) {
3355 const LocationSummary* const locations = cond->GetLocations();
3356 Register left = locations->InAt(0).AsRegister<Register>();
3357 const Register out = locations->Out().AsRegister<Register>();
3358 const Location right_loc = locations->InAt(1);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003359
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003360 // The constant case is handled by the instruction simplifier.
3361 DCHECK(!right_loc.IsConstant());
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003362
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003363 Register right = right_loc.AsRegister<Register>();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003364
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003365 // Avoid 32-bit instructions if possible.
3366 if (out == right) {
3367 std::swap(left, right);
3368 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003369
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003370 __ eor(out, left, ShifterOperand(right));
3371
3372 if (condition == kCondEQ) {
3373 __ eor(out, out, ShifterOperand(1));
3374 }
3375
3376 return;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003377 }
Anton Kirilov6f644202017-02-27 18:29:45 +00003378
Anton Kirilov5601d4e2017-05-11 19:33:50 +01003379 GenerateConditionIntegralOrNonPrimitive(cond, codegen_);
Dave Allison20dfc792014-06-16 20:44:29 -07003380}
3381
3382void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003383 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003384}
3385
3386void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003387 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003388}
3389
3390void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003391 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003392}
3393
3394void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003395 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003396}
3397
3398void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003399 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003400}
3401
3402void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003403 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003404}
3405
3406void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003407 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003408}
3409
3410void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003411 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003412}
3413
3414void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003415 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003416}
3417
3418void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003419 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003420}
3421
3422void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003423 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003424}
3425
3426void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003427 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003428}
3429
Aart Bike9f37602015-10-09 11:15:55 -07003430void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003431 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003432}
3433
3434void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003435 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003436}
3437
3438void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003439 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003440}
3441
3442void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003443 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003444}
3445
3446void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003447 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003448}
3449
3450void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003451 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003452}
3453
3454void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003455 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003456}
3457
3458void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003459 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003460}
3461
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003462void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003463 LocationSummary* locations =
3464 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003465 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003466}
3467
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003468void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01003469 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003470}
3471
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003472void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
3473 LocationSummary* locations =
3474 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3475 locations->SetOut(Location::ConstantLocation(constant));
3476}
3477
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003478void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003479 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003480}
3481
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003482void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003483 LocationSummary* locations =
3484 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003485 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003486}
3487
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003488void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003489 // Will be generated at use site.
3490}
3491
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003492void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
3493 LocationSummary* locations =
3494 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3495 locations->SetOut(Location::ConstantLocation(constant));
3496}
3497
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003498void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003499 // Will be generated at use site.
3500}
3501
3502void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
3503 LocationSummary* locations =
3504 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3505 locations->SetOut(Location::ConstantLocation(constant));
3506}
3507
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003508void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003509 // Will be generated at use site.
3510}
3511
Igor Murashkind01745e2017-04-05 16:40:31 -07003512void LocationsBuilderARM::VisitConstructorFence(HConstructorFence* constructor_fence) {
3513 constructor_fence->SetLocations(nullptr);
3514}
3515
3516void InstructionCodeGeneratorARM::VisitConstructorFence(
3517 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
3518 codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
3519}
3520
Calin Juravle27df7582015-04-17 19:12:31 +01003521void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
3522 memory_barrier->SetLocations(nullptr);
3523}
3524
3525void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00003526 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01003527}
3528
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003529void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003530 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003531}
3532
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003533void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003534 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003535}
3536
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003537void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003538 LocationSummary* locations =
3539 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003540 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003541}
3542
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003543void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003544 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003545}
3546
Calin Juravle175dc732015-08-25 15:42:32 +01003547void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3548 // The trampoline uses the same calling convention as dex calling conventions,
3549 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
3550 // the method_idx.
3551 HandleInvoke(invoke);
3552}
3553
3554void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3555 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
3556}
3557
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003558void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003559 // Explicit clinit checks triggered by static invokes must have been pruned by
3560 // art::PrepareForRegisterAllocation.
3561 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003562
Vladimir Marko68c981f2016-08-26 13:13:33 +01003563 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003564 if (intrinsic.TryDispatch(invoke)) {
3565 return;
3566 }
3567
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003568 HandleInvoke(invoke);
3569}
3570
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003571static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
3572 if (invoke->GetLocations()->Intrinsified()) {
3573 IntrinsicCodeGeneratorARM intrinsic(codegen);
3574 intrinsic.Dispatch(invoke);
3575 return true;
3576 }
3577 return false;
3578}
3579
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003580void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003581 // Explicit clinit checks triggered by static invokes must have been pruned by
3582 // art::PrepareForRegisterAllocation.
3583 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003584
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003585 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3586 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00003587 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003588
Nicolas Geoffray38207af2015-06-01 15:46:22 +01003589 LocationSummary* locations = invoke->GetLocations();
3590 codegen_->GenerateStaticOrDirectCall(
3591 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003592}
3593
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003594void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01003595 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01003596 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003597}
3598
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003599void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Vladimir Marko68c981f2016-08-26 13:13:33 +01003600 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003601 if (intrinsic.TryDispatch(invoke)) {
3602 return;
3603 }
3604
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003605 HandleInvoke(invoke);
3606}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003607
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003608void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003609 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3610 return;
3611 }
3612
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003613 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003614 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003615}
3616
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003617void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3618 HandleInvoke(invoke);
3619 // Add the hidden argument.
3620 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
3621}
3622
3623void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3624 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00003625 LocationSummary* locations = invoke->GetLocations();
3626 Register temp = locations->GetTemp(0).AsRegister<Register>();
3627 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003628 Location receiver = locations->InAt(0);
3629 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3630
Roland Levillain3b359c72015-11-17 19:35:12 +00003631 // Set the hidden argument. This is safe to do this here, as R12
3632 // won't be modified thereafter, before the `blx` (call) instruction.
3633 DCHECK_EQ(R12, hidden_reg);
3634 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003635
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003636 if (receiver.IsStackSlot()) {
3637 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00003638 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003639 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
3640 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00003641 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00003642 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003643 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003644 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00003645 // Instead of simply (possibly) unpoisoning `temp` here, we should
3646 // emit a read barrier for the previous class reference load.
3647 // However this is not required in practice, as this is an
3648 // intermediate/temporary reference and because the current
3649 // concurrent copying collector keeps the from-space memory
3650 // intact/accessible until the end of the marking phase (the
3651 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01003652 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003653 __ LoadFromOffset(kLoadWord, temp, temp,
3654 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
3655 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00003656 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003657 // temp = temp->GetImtEntryAt(method_offset);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003658 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00003659 uint32_t entry_point =
Andreas Gampe542451c2016-07-26 09:02:02 -07003660 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003661 // LR = temp->GetEntryPoint();
3662 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
3663 // LR();
3664 __ blx(LR);
3665 DCHECK(!codegen_->IsLeafMethod());
3666 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3667}
3668
Orion Hodsonac141392017-01-13 11:53:47 +00003669void LocationsBuilderARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3670 HandleInvoke(invoke);
3671}
3672
3673void InstructionCodeGeneratorARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3674 codegen_->GenerateInvokePolymorphicCall(invoke);
3675}
3676
Roland Levillain88cb1752014-10-20 16:36:47 +01003677void LocationsBuilderARM::VisitNeg(HNeg* neg) {
3678 LocationSummary* locations =
3679 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
3680 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003681 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01003682 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003683 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3684 break;
3685 }
3686 case Primitive::kPrimLong: {
3687 locations->SetInAt(0, Location::RequiresRegister());
3688 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003689 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003690 }
Roland Levillain88cb1752014-10-20 16:36:47 +01003691
Roland Levillain88cb1752014-10-20 16:36:47 +01003692 case Primitive::kPrimFloat:
3693 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003694 locations->SetInAt(0, Location::RequiresFpuRegister());
3695 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003696 break;
3697
3698 default:
3699 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3700 }
3701}
3702
3703void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
3704 LocationSummary* locations = neg->GetLocations();
3705 Location out = locations->Out();
3706 Location in = locations->InAt(0);
3707 switch (neg->GetResultType()) {
3708 case Primitive::kPrimInt:
3709 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003710 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01003711 break;
3712
3713 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003714 DCHECK(in.IsRegisterPair());
3715 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
3716 __ rsbs(out.AsRegisterPairLow<Register>(),
3717 in.AsRegisterPairLow<Register>(),
3718 ShifterOperand(0));
3719 // We cannot emit an RSC (Reverse Subtract with Carry)
3720 // instruction here, as it does not exist in the Thumb-2
3721 // instruction set. We use the following approach
3722 // using SBC and SUB instead.
3723 //
3724 // out.hi = -C
3725 __ sbc(out.AsRegisterPairHigh<Register>(),
3726 out.AsRegisterPairHigh<Register>(),
3727 ShifterOperand(out.AsRegisterPairHigh<Register>()));
3728 // out.hi = out.hi - in.hi
3729 __ sub(out.AsRegisterPairHigh<Register>(),
3730 out.AsRegisterPairHigh<Register>(),
3731 ShifterOperand(in.AsRegisterPairHigh<Register>()));
3732 break;
3733
Roland Levillain88cb1752014-10-20 16:36:47 +01003734 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003735 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003736 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00003737 break;
3738
Roland Levillain88cb1752014-10-20 16:36:47 +01003739 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003740 DCHECK(in.IsFpuRegisterPair());
3741 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3742 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01003743 break;
3744
3745 default:
3746 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3747 }
3748}
3749
Roland Levillaindff1f282014-11-05 14:15:05 +00003750void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00003751 Primitive::Type result_type = conversion->GetResultType();
3752 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003753 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00003754
Roland Levillain5b3ee562015-04-14 16:02:41 +01003755 // The float-to-long, double-to-long and long-to-float type conversions
3756 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00003757 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01003758 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
3759 && result_type == Primitive::kPrimLong)
3760 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003761 ? LocationSummary::kCallOnMainOnly
Roland Levillain624279f2014-12-04 11:54:28 +00003762 : LocationSummary::kNoCall;
3763 LocationSummary* locations =
3764 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
3765
David Brazdilb2bd1c52015-03-25 11:17:37 +00003766 // The Java language does not allow treating boolean as an integral type but
3767 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00003768
Roland Levillaindff1f282014-11-05 14:15:05 +00003769 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003770 case Primitive::kPrimByte:
3771 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003772 case Primitive::kPrimLong:
3773 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003774 case Primitive::kPrimBoolean:
3775 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003776 case Primitive::kPrimShort:
3777 case Primitive::kPrimInt:
3778 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003779 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003780 locations->SetInAt(0, Location::RequiresRegister());
3781 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3782 break;
3783
3784 default:
3785 LOG(FATAL) << "Unexpected type conversion from " << input_type
3786 << " to " << result_type;
3787 }
3788 break;
3789
Roland Levillain01a8d712014-11-14 16:27:39 +00003790 case Primitive::kPrimShort:
3791 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003792 case Primitive::kPrimLong:
3793 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003794 case Primitive::kPrimBoolean:
3795 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00003796 case Primitive::kPrimByte:
3797 case Primitive::kPrimInt:
3798 case Primitive::kPrimChar:
3799 // Processing a Dex `int-to-short' instruction.
3800 locations->SetInAt(0, Location::RequiresRegister());
3801 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3802 break;
3803
3804 default:
3805 LOG(FATAL) << "Unexpected type conversion from " << input_type
3806 << " to " << result_type;
3807 }
3808 break;
3809
Roland Levillain946e1432014-11-11 17:35:19 +00003810 case Primitive::kPrimInt:
3811 switch (input_type) {
3812 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00003813 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00003814 locations->SetInAt(0, Location::Any());
3815 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3816 break;
3817
3818 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00003819 // Processing a Dex `float-to-int' instruction.
3820 locations->SetInAt(0, Location::RequiresFpuRegister());
3821 locations->SetOut(Location::RequiresRegister());
3822 locations->AddTemp(Location::RequiresFpuRegister());
3823 break;
3824
Roland Levillain946e1432014-11-11 17:35:19 +00003825 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003826 // Processing a Dex `double-to-int' instruction.
3827 locations->SetInAt(0, Location::RequiresFpuRegister());
3828 locations->SetOut(Location::RequiresRegister());
3829 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00003830 break;
3831
3832 default:
3833 LOG(FATAL) << "Unexpected type conversion from " << input_type
3834 << " to " << result_type;
3835 }
3836 break;
3837
Roland Levillaindff1f282014-11-05 14:15:05 +00003838 case Primitive::kPrimLong:
3839 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003840 case Primitive::kPrimBoolean:
3841 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00003842 case Primitive::kPrimByte:
3843 case Primitive::kPrimShort:
3844 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00003845 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003846 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00003847 locations->SetInAt(0, Location::RequiresRegister());
3848 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3849 break;
3850
Roland Levillain624279f2014-12-04 11:54:28 +00003851 case Primitive::kPrimFloat: {
3852 // Processing a Dex `float-to-long' instruction.
3853 InvokeRuntimeCallingConvention calling_convention;
3854 locations->SetInAt(0, Location::FpuRegisterLocation(
3855 calling_convention.GetFpuRegisterAt(0)));
3856 locations->SetOut(Location::RegisterPairLocation(R0, R1));
3857 break;
3858 }
3859
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003860 case Primitive::kPrimDouble: {
3861 // Processing a Dex `double-to-long' instruction.
3862 InvokeRuntimeCallingConvention calling_convention;
3863 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3864 calling_convention.GetFpuRegisterAt(0),
3865 calling_convention.GetFpuRegisterAt(1)));
3866 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00003867 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003868 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003869
3870 default:
3871 LOG(FATAL) << "Unexpected type conversion from " << input_type
3872 << " to " << result_type;
3873 }
3874 break;
3875
Roland Levillain981e4542014-11-14 11:47:14 +00003876 case Primitive::kPrimChar:
3877 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003878 case Primitive::kPrimLong:
3879 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003880 case Primitive::kPrimBoolean:
3881 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00003882 case Primitive::kPrimByte:
3883 case Primitive::kPrimShort:
3884 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00003885 // Processing a Dex `int-to-char' instruction.
3886 locations->SetInAt(0, Location::RequiresRegister());
3887 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3888 break;
3889
3890 default:
3891 LOG(FATAL) << "Unexpected type conversion from " << input_type
3892 << " to " << result_type;
3893 }
3894 break;
3895
Roland Levillaindff1f282014-11-05 14:15:05 +00003896 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00003897 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003898 case Primitive::kPrimBoolean:
3899 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003900 case Primitive::kPrimByte:
3901 case Primitive::kPrimShort:
3902 case Primitive::kPrimInt:
3903 case Primitive::kPrimChar:
3904 // Processing a Dex `int-to-float' instruction.
3905 locations->SetInAt(0, Location::RequiresRegister());
3906 locations->SetOut(Location::RequiresFpuRegister());
3907 break;
3908
Roland Levillain5b3ee562015-04-14 16:02:41 +01003909 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00003910 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01003911 InvokeRuntimeCallingConvention calling_convention;
3912 locations->SetInAt(0, Location::RegisterPairLocation(
3913 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3914 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00003915 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01003916 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00003917
Roland Levillaincff13742014-11-17 14:32:17 +00003918 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003919 // Processing a Dex `double-to-float' instruction.
3920 locations->SetInAt(0, Location::RequiresFpuRegister());
3921 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003922 break;
3923
3924 default:
3925 LOG(FATAL) << "Unexpected type conversion from " << input_type
3926 << " to " << result_type;
3927 };
3928 break;
3929
Roland Levillaindff1f282014-11-05 14:15:05 +00003930 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00003931 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003932 case Primitive::kPrimBoolean:
3933 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003934 case Primitive::kPrimByte:
3935 case Primitive::kPrimShort:
3936 case Primitive::kPrimInt:
3937 case Primitive::kPrimChar:
3938 // Processing a Dex `int-to-double' instruction.
3939 locations->SetInAt(0, Location::RequiresRegister());
3940 locations->SetOut(Location::RequiresFpuRegister());
3941 break;
3942
3943 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00003944 // Processing a Dex `long-to-double' instruction.
3945 locations->SetInAt(0, Location::RequiresRegister());
3946 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01003947 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00003948 locations->AddTemp(Location::RequiresFpuRegister());
3949 break;
3950
Roland Levillaincff13742014-11-17 14:32:17 +00003951 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003952 // Processing a Dex `float-to-double' instruction.
3953 locations->SetInAt(0, Location::RequiresFpuRegister());
3954 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003955 break;
3956
3957 default:
3958 LOG(FATAL) << "Unexpected type conversion from " << input_type
3959 << " to " << result_type;
3960 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003961 break;
3962
3963 default:
3964 LOG(FATAL) << "Unexpected type conversion from " << input_type
3965 << " to " << result_type;
3966 }
3967}
3968
3969void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
3970 LocationSummary* locations = conversion->GetLocations();
3971 Location out = locations->Out();
3972 Location in = locations->InAt(0);
3973 Primitive::Type result_type = conversion->GetResultType();
3974 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003975 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00003976 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003977 case Primitive::kPrimByte:
3978 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003979 case Primitive::kPrimLong:
3980 // Type conversion from long to byte is a result of code transformations.
3981 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
3982 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003983 case Primitive::kPrimBoolean:
3984 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003985 case Primitive::kPrimShort:
3986 case Primitive::kPrimInt:
3987 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003988 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003989 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00003990 break;
3991
3992 default:
3993 LOG(FATAL) << "Unexpected type conversion from " << input_type
3994 << " to " << result_type;
3995 }
3996 break;
3997
Roland Levillain01a8d712014-11-14 16:27:39 +00003998 case Primitive::kPrimShort:
3999 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00004000 case Primitive::kPrimLong:
4001 // Type conversion from long to short is a result of code transformations.
4002 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
4003 break;
David Brazdil46e2a392015-03-16 17:31:52 +00004004 case Primitive::kPrimBoolean:
4005 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00004006 case Primitive::kPrimByte:
4007 case Primitive::kPrimInt:
4008 case Primitive::kPrimChar:
4009 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004010 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00004011 break;
4012
4013 default:
4014 LOG(FATAL) << "Unexpected type conversion from " << input_type
4015 << " to " << result_type;
4016 }
4017 break;
4018
Roland Levillain946e1432014-11-11 17:35:19 +00004019 case Primitive::kPrimInt:
4020 switch (input_type) {
4021 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00004022 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00004023 DCHECK(out.IsRegister());
4024 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004025 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00004026 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004027 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00004028 } else {
4029 DCHECK(in.IsConstant());
4030 DCHECK(in.GetConstant()->IsLongConstant());
4031 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004032 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00004033 }
4034 break;
4035
Roland Levillain3f8f9362014-12-02 17:45:01 +00004036 case Primitive::kPrimFloat: {
4037 // Processing a Dex `float-to-int' instruction.
4038 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01004039 __ vcvtis(temp, in.AsFpuRegister<SRegister>());
Roland Levillain3f8f9362014-12-02 17:45:01 +00004040 __ vmovrs(out.AsRegister<Register>(), temp);
4041 break;
4042 }
4043
Roland Levillain4c0b61f2014-12-05 12:06:01 +00004044 case Primitive::kPrimDouble: {
4045 // Processing a Dex `double-to-int' instruction.
4046 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01004047 __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00004048 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00004049 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00004050 }
Roland Levillain946e1432014-11-11 17:35:19 +00004051
4052 default:
4053 LOG(FATAL) << "Unexpected type conversion from " << input_type
4054 << " to " << result_type;
4055 }
4056 break;
4057
Roland Levillaindff1f282014-11-05 14:15:05 +00004058 case Primitive::kPrimLong:
4059 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00004060 case Primitive::kPrimBoolean:
4061 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00004062 case Primitive::kPrimByte:
4063 case Primitive::kPrimShort:
4064 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00004065 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00004066 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00004067 DCHECK(out.IsRegisterPair());
4068 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004069 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00004070 // Sign extension.
4071 __ Asr(out.AsRegisterPairHigh<Register>(),
4072 out.AsRegisterPairLow<Register>(),
4073 31);
4074 break;
4075
4076 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00004077 // Processing a Dex `float-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004078 codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004079 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00004080 break;
4081
Roland Levillaindff1f282014-11-05 14:15:05 +00004082 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00004083 // Processing a Dex `double-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004084 codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004085 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00004086 break;
4087
4088 default:
4089 LOG(FATAL) << "Unexpected type conversion from " << input_type
4090 << " to " << result_type;
4091 }
4092 break;
4093
Roland Levillain981e4542014-11-14 11:47:14 +00004094 case Primitive::kPrimChar:
4095 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00004096 case Primitive::kPrimLong:
4097 // Type conversion from long to char is a result of code transformations.
4098 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
4099 break;
David Brazdil46e2a392015-03-16 17:31:52 +00004100 case Primitive::kPrimBoolean:
4101 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00004102 case Primitive::kPrimByte:
4103 case Primitive::kPrimShort:
4104 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00004105 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004106 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00004107 break;
4108
4109 default:
4110 LOG(FATAL) << "Unexpected type conversion from " << input_type
4111 << " to " << result_type;
4112 }
4113 break;
4114
Roland Levillaindff1f282014-11-05 14:15:05 +00004115 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00004116 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00004117 case Primitive::kPrimBoolean:
4118 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00004119 case Primitive::kPrimByte:
4120 case Primitive::kPrimShort:
4121 case Primitive::kPrimInt:
4122 case Primitive::kPrimChar: {
4123 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004124 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
4125 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00004126 break;
4127 }
4128
Roland Levillain5b3ee562015-04-14 16:02:41 +01004129 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00004130 // Processing a Dex `long-to-float' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004131 codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004132 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00004133 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00004134
Roland Levillaincff13742014-11-17 14:32:17 +00004135 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00004136 // Processing a Dex `double-to-float' instruction.
4137 __ vcvtsd(out.AsFpuRegister<SRegister>(),
4138 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00004139 break;
4140
4141 default:
4142 LOG(FATAL) << "Unexpected type conversion from " << input_type
4143 << " to " << result_type;
4144 };
4145 break;
4146
Roland Levillaindff1f282014-11-05 14:15:05 +00004147 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00004148 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00004149 case Primitive::kPrimBoolean:
4150 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00004151 case Primitive::kPrimByte:
4152 case Primitive::kPrimShort:
4153 case Primitive::kPrimInt:
4154 case Primitive::kPrimChar: {
4155 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004156 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00004157 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4158 out.AsFpuRegisterPairLow<SRegister>());
4159 break;
4160 }
4161
Roland Levillain647b9ed2014-11-27 12:06:00 +00004162 case Primitive::kPrimLong: {
4163 // Processing a Dex `long-to-double' instruction.
4164 Register low = in.AsRegisterPairLow<Register>();
4165 Register high = in.AsRegisterPairHigh<Register>();
4166 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
4167 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01004168 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00004169 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01004170 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
4171 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00004172
Roland Levillain682393c2015-04-14 15:57:52 +01004173 // temp_d = int-to-double(high)
4174 __ vmovsr(temp_s, high);
4175 __ vcvtdi(temp_d, temp_s);
4176 // constant_d = k2Pow32EncodingForDouble
4177 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
4178 // out_d = unsigned-to-double(low)
4179 __ vmovsr(out_s, low);
4180 __ vcvtdu(out_d, out_s);
4181 // out_d += temp_d * constant_d
4182 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00004183 break;
4184 }
4185
Roland Levillaincff13742014-11-17 14:32:17 +00004186 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00004187 // Processing a Dex `float-to-double' instruction.
4188 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4189 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00004190 break;
4191
4192 default:
4193 LOG(FATAL) << "Unexpected type conversion from " << input_type
4194 << " to " << result_type;
4195 };
Roland Levillaindff1f282014-11-05 14:15:05 +00004196 break;
4197
4198 default:
4199 LOG(FATAL) << "Unexpected type conversion from " << input_type
4200 << " to " << result_type;
4201 }
4202}
4203
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004204void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004205 LocationSummary* locations =
4206 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004207 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004208 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004209 locations->SetInAt(0, Location::RequiresRegister());
4210 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004211 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4212 break;
4213 }
4214
4215 case Primitive::kPrimLong: {
4216 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01004217 locations->SetInAt(1, ArmEncodableConstantOrRegister(add->InputAt(1), ADD));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004218 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004219 break;
4220 }
4221
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004222 case Primitive::kPrimFloat:
4223 case Primitive::kPrimDouble: {
4224 locations->SetInAt(0, Location::RequiresFpuRegister());
4225 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004226 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004227 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004228 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004229
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004230 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004231 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004232 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004233}
4234
4235void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
4236 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004237 Location out = locations->Out();
4238 Location first = locations->InAt(0);
4239 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004240 switch (add->GetResultType()) {
4241 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004242 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004243 __ add(out.AsRegister<Register>(),
4244 first.AsRegister<Register>(),
4245 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004246 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004247 __ AddConstant(out.AsRegister<Register>(),
4248 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004249 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004250 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004251 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004252
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004253 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01004254 if (second.IsConstant()) {
4255 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
4256 GenerateAddLongConst(out, first, value);
4257 } else {
4258 DCHECK(second.IsRegisterPair());
4259 __ adds(out.AsRegisterPairLow<Register>(),
4260 first.AsRegisterPairLow<Register>(),
4261 ShifterOperand(second.AsRegisterPairLow<Register>()));
4262 __ adc(out.AsRegisterPairHigh<Register>(),
4263 first.AsRegisterPairHigh<Register>(),
4264 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4265 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004266 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004267 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004268
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004269 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00004270 __ vadds(out.AsFpuRegister<SRegister>(),
4271 first.AsFpuRegister<SRegister>(),
4272 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004273 break;
4274
4275 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004276 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4277 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4278 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004279 break;
4280
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004281 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004282 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004283 }
4284}
4285
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004286void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004287 LocationSummary* locations =
4288 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004289 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004290 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004291 locations->SetInAt(0, Location::RequiresRegister());
4292 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004293 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4294 break;
4295 }
4296
4297 case Primitive::kPrimLong: {
4298 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01004299 locations->SetInAt(1, ArmEncodableConstantOrRegister(sub->InputAt(1), SUB));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004300 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004301 break;
4302 }
Calin Juravle11351682014-10-23 15:38:15 +01004303 case Primitive::kPrimFloat:
4304 case Primitive::kPrimDouble: {
4305 locations->SetInAt(0, Location::RequiresFpuRegister());
4306 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004307 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004308 break;
Calin Juravle11351682014-10-23 15:38:15 +01004309 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004310 default:
Calin Juravle11351682014-10-23 15:38:15 +01004311 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004312 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004313}
4314
4315void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
4316 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01004317 Location out = locations->Out();
4318 Location first = locations->InAt(0);
4319 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004320 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004321 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01004322 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004323 __ sub(out.AsRegister<Register>(),
4324 first.AsRegister<Register>(),
4325 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004326 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004327 __ AddConstant(out.AsRegister<Register>(),
4328 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01004329 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004330 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004331 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004332 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004333
Calin Juravle11351682014-10-23 15:38:15 +01004334 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01004335 if (second.IsConstant()) {
4336 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
4337 GenerateAddLongConst(out, first, -value);
4338 } else {
4339 DCHECK(second.IsRegisterPair());
4340 __ subs(out.AsRegisterPairLow<Register>(),
4341 first.AsRegisterPairLow<Register>(),
4342 ShifterOperand(second.AsRegisterPairLow<Register>()));
4343 __ sbc(out.AsRegisterPairHigh<Register>(),
4344 first.AsRegisterPairHigh<Register>(),
4345 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4346 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004347 break;
Calin Juravle11351682014-10-23 15:38:15 +01004348 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004349
Calin Juravle11351682014-10-23 15:38:15 +01004350 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004351 __ vsubs(out.AsFpuRegister<SRegister>(),
4352 first.AsFpuRegister<SRegister>(),
4353 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004354 break;
Calin Juravle11351682014-10-23 15:38:15 +01004355 }
4356
4357 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004358 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4359 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4360 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01004361 break;
4362 }
4363
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004364
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004365 default:
Calin Juravle11351682014-10-23 15:38:15 +01004366 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004367 }
4368}
4369
Calin Juravle34bacdf2014-10-07 20:23:36 +01004370void LocationsBuilderARM::VisitMul(HMul* mul) {
4371 LocationSummary* locations =
4372 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
4373 switch (mul->GetResultType()) {
4374 case Primitive::kPrimInt:
4375 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004376 locations->SetInAt(0, Location::RequiresRegister());
4377 locations->SetInAt(1, Location::RequiresRegister());
4378 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01004379 break;
4380 }
4381
Calin Juravleb5bfa962014-10-21 18:02:24 +01004382 case Primitive::kPrimFloat:
4383 case Primitive::kPrimDouble: {
4384 locations->SetInAt(0, Location::RequiresFpuRegister());
4385 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004386 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01004387 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01004388 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01004389
4390 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01004391 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01004392 }
4393}
4394
4395void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
4396 LocationSummary* locations = mul->GetLocations();
4397 Location out = locations->Out();
4398 Location first = locations->InAt(0);
4399 Location second = locations->InAt(1);
4400 switch (mul->GetResultType()) {
4401 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00004402 __ mul(out.AsRegister<Register>(),
4403 first.AsRegister<Register>(),
4404 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01004405 break;
4406 }
4407 case Primitive::kPrimLong: {
4408 Register out_hi = out.AsRegisterPairHigh<Register>();
4409 Register out_lo = out.AsRegisterPairLow<Register>();
4410 Register in1_hi = first.AsRegisterPairHigh<Register>();
4411 Register in1_lo = first.AsRegisterPairLow<Register>();
4412 Register in2_hi = second.AsRegisterPairHigh<Register>();
4413 Register in2_lo = second.AsRegisterPairLow<Register>();
4414
4415 // Extra checks to protect caused by the existence of R1_R2.
4416 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
4417 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
4418 DCHECK_NE(out_hi, in1_lo);
4419 DCHECK_NE(out_hi, in2_lo);
4420
4421 // input: in1 - 64 bits, in2 - 64 bits
4422 // output: out
4423 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
4424 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
4425 // parts: out.lo = (in1.lo * in2.lo)[31:0]
4426
4427 // IP <- in1.lo * in2.hi
4428 __ mul(IP, in1_lo, in2_hi);
4429 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
4430 __ mla(out_hi, in1_hi, in2_lo, IP);
4431 // out.lo <- (in1.lo * in2.lo)[31:0];
4432 __ umull(out_lo, IP, in1_lo, in2_lo);
4433 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
4434 __ add(out_hi, out_hi, ShifterOperand(IP));
4435 break;
4436 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01004437
4438 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004439 __ vmuls(out.AsFpuRegister<SRegister>(),
4440 first.AsFpuRegister<SRegister>(),
4441 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01004442 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01004443 }
4444
4445 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004446 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4447 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4448 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01004449 break;
4450 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01004451
4452 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01004453 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01004454 }
4455}
4456
Zheng Xuc6667102015-05-15 16:08:45 +08004457void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
4458 DCHECK(instruction->IsDiv() || instruction->IsRem());
4459 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4460
4461 LocationSummary* locations = instruction->GetLocations();
4462 Location second = locations->InAt(1);
4463 DCHECK(second.IsConstant());
4464
4465 Register out = locations->Out().AsRegister<Register>();
4466 Register dividend = locations->InAt(0).AsRegister<Register>();
4467 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4468 DCHECK(imm == 1 || imm == -1);
4469
4470 if (instruction->IsRem()) {
4471 __ LoadImmediate(out, 0);
4472 } else {
4473 if (imm == 1) {
4474 __ Mov(out, dividend);
4475 } else {
4476 __ rsb(out, dividend, ShifterOperand(0));
4477 }
4478 }
4479}
4480
4481void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
4482 DCHECK(instruction->IsDiv() || instruction->IsRem());
4483 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4484
4485 LocationSummary* locations = instruction->GetLocations();
4486 Location second = locations->InAt(1);
4487 DCHECK(second.IsConstant());
4488
4489 Register out = locations->Out().AsRegister<Register>();
4490 Register dividend = locations->InAt(0).AsRegister<Register>();
4491 Register temp = locations->GetTemp(0).AsRegister<Register>();
4492 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004493 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08004494 int ctz_imm = CTZ(abs_imm);
4495
4496 if (ctz_imm == 1) {
4497 __ Lsr(temp, dividend, 32 - ctz_imm);
4498 } else {
4499 __ Asr(temp, dividend, 31);
4500 __ Lsr(temp, temp, 32 - ctz_imm);
4501 }
4502 __ add(out, temp, ShifterOperand(dividend));
4503
4504 if (instruction->IsDiv()) {
4505 __ Asr(out, out, ctz_imm);
4506 if (imm < 0) {
4507 __ rsb(out, out, ShifterOperand(0));
4508 }
4509 } else {
4510 __ ubfx(out, out, 0, ctz_imm);
4511 __ sub(out, out, ShifterOperand(temp));
4512 }
4513}
4514
4515void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
4516 DCHECK(instruction->IsDiv() || instruction->IsRem());
4517 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4518
4519 LocationSummary* locations = instruction->GetLocations();
4520 Location second = locations->InAt(1);
4521 DCHECK(second.IsConstant());
4522
4523 Register out = locations->Out().AsRegister<Register>();
4524 Register dividend = locations->InAt(0).AsRegister<Register>();
4525 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4526 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4527 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4528
4529 int64_t magic;
4530 int shift;
4531 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
4532
4533 __ LoadImmediate(temp1, magic);
4534 __ smull(temp2, temp1, dividend, temp1);
4535
4536 if (imm > 0 && magic < 0) {
4537 __ add(temp1, temp1, ShifterOperand(dividend));
4538 } else if (imm < 0 && magic > 0) {
4539 __ sub(temp1, temp1, ShifterOperand(dividend));
4540 }
4541
4542 if (shift != 0) {
4543 __ Asr(temp1, temp1, shift);
4544 }
4545
4546 if (instruction->IsDiv()) {
4547 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
4548 } else {
4549 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
4550 // TODO: Strength reduction for mls.
4551 __ LoadImmediate(temp2, imm);
4552 __ mls(out, temp1, temp2, dividend);
4553 }
4554}
4555
4556void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
4557 DCHECK(instruction->IsDiv() || instruction->IsRem());
4558 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4559
4560 LocationSummary* locations = instruction->GetLocations();
4561 Location second = locations->InAt(1);
4562 DCHECK(second.IsConstant());
4563
4564 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4565 if (imm == 0) {
4566 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
4567 } else if (imm == 1 || imm == -1) {
4568 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004569 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004570 DivRemByPowerOfTwo(instruction);
4571 } else {
4572 DCHECK(imm <= -2 || imm >= 2);
4573 GenerateDivRemWithAnyConstant(instruction);
4574 }
4575}
4576
Calin Juravle7c4954d2014-10-28 16:57:40 +00004577void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004578 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4579 if (div->GetResultType() == Primitive::kPrimLong) {
4580 // pLdiv runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004581 call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004582 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
4583 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004584 } else if (div->GetResultType() == Primitive::kPrimInt &&
4585 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4586 // pIdivmod runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004587 call_kind = LocationSummary::kCallOnMainOnly;
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004588 }
4589
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004590 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
4591
Calin Juravle7c4954d2014-10-28 16:57:40 +00004592 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004593 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004594 if (div->InputAt(1)->IsConstant()) {
4595 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004596 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004597 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004598 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
4599 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004600 // No temp register required.
4601 } else {
4602 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004603 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004604 locations->AddTemp(Location::RequiresRegister());
4605 }
4606 }
4607 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004608 locations->SetInAt(0, Location::RequiresRegister());
4609 locations->SetInAt(1, Location::RequiresRegister());
4610 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4611 } else {
4612 InvokeRuntimeCallingConvention calling_convention;
4613 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4614 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004615 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004616 // we only need the former.
4617 locations->SetOut(Location::RegisterLocation(R0));
4618 }
Calin Juravled0d48522014-11-04 16:40:20 +00004619 break;
4620 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00004621 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004622 InvokeRuntimeCallingConvention calling_convention;
4623 locations->SetInAt(0, Location::RegisterPairLocation(
4624 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4625 locations->SetInAt(1, Location::RegisterPairLocation(
4626 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004627 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00004628 break;
4629 }
4630 case Primitive::kPrimFloat:
4631 case Primitive::kPrimDouble: {
4632 locations->SetInAt(0, Location::RequiresFpuRegister());
4633 locations->SetInAt(1, Location::RequiresFpuRegister());
4634 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4635 break;
4636 }
4637
4638 default:
4639 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4640 }
4641}
4642
4643void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
4644 LocationSummary* locations = div->GetLocations();
4645 Location out = locations->Out();
4646 Location first = locations->InAt(0);
4647 Location second = locations->InAt(1);
4648
4649 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004650 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004651 if (second.IsConstant()) {
4652 GenerateDivRemConstantIntegral(div);
4653 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004654 __ sdiv(out.AsRegister<Register>(),
4655 first.AsRegister<Register>(),
4656 second.AsRegister<Register>());
4657 } else {
4658 InvokeRuntimeCallingConvention calling_convention;
4659 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4660 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4661 DCHECK_EQ(R0, out.AsRegister<Register>());
4662
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004663 codegen_->InvokeRuntime(kQuickIdivmod, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004664 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004665 }
Calin Juravled0d48522014-11-04 16:40:20 +00004666 break;
4667 }
4668
Calin Juravle7c4954d2014-10-28 16:57:40 +00004669 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004670 InvokeRuntimeCallingConvention calling_convention;
4671 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
4672 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
4673 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
4674 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
4675 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004676 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004677
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004678 codegen_->InvokeRuntime(kQuickLdiv, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004679 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00004680 break;
4681 }
4682
4683 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004684 __ vdivs(out.AsFpuRegister<SRegister>(),
4685 first.AsFpuRegister<SRegister>(),
4686 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004687 break;
4688 }
4689
4690 case Primitive::kPrimDouble: {
4691 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4692 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4693 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
4694 break;
4695 }
4696
4697 default:
4698 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4699 }
4700}
4701
Calin Juravlebacfec32014-11-14 15:54:36 +00004702void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004703 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004704
4705 // Most remainders are implemented in the runtime.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004706 LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004707 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
4708 // sdiv will be replaced by other instruction sequence.
4709 call_kind = LocationSummary::kNoCall;
4710 } else if ((rem->GetResultType() == Primitive::kPrimInt)
4711 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004712 // Have hardware divide instruction for int, do it with three instructions.
4713 call_kind = LocationSummary::kNoCall;
4714 }
4715
Calin Juravlebacfec32014-11-14 15:54:36 +00004716 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
4717
Calin Juravled2ec87d2014-12-08 14:24:46 +00004718 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004719 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004720 if (rem->InputAt(1)->IsConstant()) {
4721 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004722 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004723 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004724 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
4725 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004726 // No temp register required.
4727 } else {
4728 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004729 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004730 locations->AddTemp(Location::RequiresRegister());
4731 }
4732 }
4733 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004734 locations->SetInAt(0, Location::RequiresRegister());
4735 locations->SetInAt(1, Location::RequiresRegister());
4736 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4737 locations->AddTemp(Location::RequiresRegister());
4738 } else {
4739 InvokeRuntimeCallingConvention calling_convention;
4740 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4741 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004742 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004743 // we only need the latter.
4744 locations->SetOut(Location::RegisterLocation(R1));
4745 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004746 break;
4747 }
4748 case Primitive::kPrimLong: {
4749 InvokeRuntimeCallingConvention calling_convention;
4750 locations->SetInAt(0, Location::RegisterPairLocation(
4751 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4752 locations->SetInAt(1, Location::RegisterPairLocation(
4753 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4754 // The runtime helper puts the output in R2,R3.
4755 locations->SetOut(Location::RegisterPairLocation(R2, R3));
4756 break;
4757 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00004758 case Primitive::kPrimFloat: {
4759 InvokeRuntimeCallingConvention calling_convention;
4760 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
4761 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
4762 locations->SetOut(Location::FpuRegisterLocation(S0));
4763 break;
4764 }
4765
Calin Juravlebacfec32014-11-14 15:54:36 +00004766 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004767 InvokeRuntimeCallingConvention calling_convention;
4768 locations->SetInAt(0, Location::FpuRegisterPairLocation(
4769 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
4770 locations->SetInAt(1, Location::FpuRegisterPairLocation(
4771 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
4772 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00004773 break;
4774 }
4775
4776 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004777 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004778 }
4779}
4780
4781void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
4782 LocationSummary* locations = rem->GetLocations();
4783 Location out = locations->Out();
4784 Location first = locations->InAt(0);
4785 Location second = locations->InAt(1);
4786
Calin Juravled2ec87d2014-12-08 14:24:46 +00004787 Primitive::Type type = rem->GetResultType();
4788 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004789 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004790 if (second.IsConstant()) {
4791 GenerateDivRemConstantIntegral(rem);
4792 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004793 Register reg1 = first.AsRegister<Register>();
4794 Register reg2 = second.AsRegister<Register>();
4795 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004796
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004797 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004798 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004799 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004800 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004801 } else {
4802 InvokeRuntimeCallingConvention calling_convention;
4803 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4804 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4805 DCHECK_EQ(R1, out.AsRegister<Register>());
4806
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004807 codegen_->InvokeRuntime(kQuickIdivmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004808 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004809 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004810 break;
4811 }
4812
4813 case Primitive::kPrimLong: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004814 codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004815 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004816 break;
4817 }
4818
Calin Juravled2ec87d2014-12-08 14:24:46 +00004819 case Primitive::kPrimFloat: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004820 codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004821 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00004822 break;
4823 }
4824
Calin Juravlebacfec32014-11-14 15:54:36 +00004825 case Primitive::kPrimDouble: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004826 codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004827 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004828 break;
4829 }
4830
4831 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004832 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004833 }
4834}
4835
Calin Juravled0d48522014-11-04 16:40:20 +00004836void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004837 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004838 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00004839}
4840
4841void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01004842 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00004843 codegen_->AddSlowPath(slow_path);
4844
4845 LocationSummary* locations = instruction->GetLocations();
4846 Location value = locations->InAt(0);
4847
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004848 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00004849 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06004850 case Primitive::kPrimByte:
4851 case Primitive::kPrimChar:
4852 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004853 case Primitive::kPrimInt: {
4854 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004855 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004856 } else {
4857 DCHECK(value.IsConstant()) << value;
4858 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
4859 __ b(slow_path->GetEntryLabel());
4860 }
4861 }
4862 break;
4863 }
4864 case Primitive::kPrimLong: {
4865 if (value.IsRegisterPair()) {
4866 __ orrs(IP,
4867 value.AsRegisterPairLow<Register>(),
4868 ShifterOperand(value.AsRegisterPairHigh<Register>()));
4869 __ b(slow_path->GetEntryLabel(), EQ);
4870 } else {
4871 DCHECK(value.IsConstant()) << value;
4872 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4873 __ b(slow_path->GetEntryLabel());
4874 }
4875 }
4876 break;
4877 default:
4878 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
4879 }
4880 }
Calin Juravled0d48522014-11-04 16:40:20 +00004881}
4882
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004883void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
4884 Register in = locations->InAt(0).AsRegister<Register>();
4885 Location rhs = locations->InAt(1);
4886 Register out = locations->Out().AsRegister<Register>();
4887
4888 if (rhs.IsConstant()) {
4889 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
4890 // so map all rotations to a +ve. equivalent in that range.
4891 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
4892 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
4893 if (rot) {
4894 // Rotate, mapping left rotations to right equivalents if necessary.
4895 // (e.g. left by 2 bits == right by 30.)
4896 __ Ror(out, in, rot);
4897 } else if (out != in) {
4898 __ Mov(out, in);
4899 }
4900 } else {
4901 __ Ror(out, in, rhs.AsRegister<Register>());
4902 }
4903}
4904
4905// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
4906// rotates by swapping input regs (effectively rotating by the first 32-bits of
4907// a larger rotation) or flipping direction (thus treating larger right/left
4908// rotations as sub-word sized rotations in the other direction) as appropriate.
Anton Kirilov6f644202017-02-27 18:29:45 +00004909void InstructionCodeGeneratorARM::HandleLongRotate(HRor* ror) {
4910 LocationSummary* locations = ror->GetLocations();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004911 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
4912 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
4913 Location rhs = locations->InAt(1);
4914 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
4915 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
4916
4917 if (rhs.IsConstant()) {
4918 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
4919 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00004920 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004921 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
4922 // logic below to a simple pair of binary orr.
4923 // (e.g. 34 bits == in_reg swap + 2 bits right.)
4924 if (rot >= kArmBitsPerWord) {
4925 rot -= kArmBitsPerWord;
4926 std::swap(in_reg_hi, in_reg_lo);
4927 }
4928 // Rotate, or mov to out for zero or word size rotations.
4929 if (rot != 0u) {
4930 __ Lsr(out_reg_hi, in_reg_hi, rot);
4931 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
4932 __ Lsr(out_reg_lo, in_reg_lo, rot);
4933 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
4934 } else {
4935 __ Mov(out_reg_lo, in_reg_lo);
4936 __ Mov(out_reg_hi, in_reg_hi);
4937 }
4938 } else {
4939 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
4940 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
4941 Label end;
4942 Label shift_by_32_plus_shift_right;
Anton Kirilov6f644202017-02-27 18:29:45 +00004943 Label* final_label = codegen_->GetFinalLabel(ror, &end);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004944
4945 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
4946 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
4947 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
4948 __ b(&shift_by_32_plus_shift_right, CC);
4949
4950 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
4951 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
4952 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
4953 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4954 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4955 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4956 __ Lsr(shift_left, in_reg_hi, shift_right);
4957 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
Anton Kirilov6f644202017-02-27 18:29:45 +00004958 __ b(final_label);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004959
4960 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
4961 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
4962 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
4963 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
4964 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4965 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4966 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4967 __ Lsl(shift_right, in_reg_hi, shift_left);
4968 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
4969
Anton Kirilov6f644202017-02-27 18:29:45 +00004970 if (end.IsLinked()) {
4971 __ Bind(&end);
4972 }
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004973 }
4974}
Roland Levillain22c49222016-03-18 14:04:28 +00004975
4976void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004977 LocationSummary* locations =
4978 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
4979 switch (ror->GetResultType()) {
4980 case Primitive::kPrimInt: {
4981 locations->SetInAt(0, Location::RequiresRegister());
4982 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
4983 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4984 break;
4985 }
4986 case Primitive::kPrimLong: {
4987 locations->SetInAt(0, Location::RequiresRegister());
4988 if (ror->InputAt(1)->IsConstant()) {
4989 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
4990 } else {
4991 locations->SetInAt(1, Location::RequiresRegister());
4992 locations->AddTemp(Location::RequiresRegister());
4993 locations->AddTemp(Location::RequiresRegister());
4994 }
4995 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4996 break;
4997 }
4998 default:
4999 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
5000 }
5001}
5002
Roland Levillain22c49222016-03-18 14:04:28 +00005003void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00005004 LocationSummary* locations = ror->GetLocations();
5005 Primitive::Type type = ror->GetResultType();
5006 switch (type) {
5007 case Primitive::kPrimInt: {
5008 HandleIntegerRotate(locations);
5009 break;
5010 }
5011 case Primitive::kPrimLong: {
Anton Kirilov6f644202017-02-27 18:29:45 +00005012 HandleLongRotate(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00005013 break;
5014 }
5015 default:
5016 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00005017 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00005018 }
5019}
5020
Calin Juravle9aec02f2014-11-18 23:06:35 +00005021void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
5022 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
5023
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005024 LocationSummary* locations =
5025 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00005026
5027 switch (op->GetResultType()) {
5028 case Primitive::kPrimInt: {
5029 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005030 if (op->InputAt(1)->IsConstant()) {
5031 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
5032 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5033 } else {
5034 locations->SetInAt(1, Location::RequiresRegister());
5035 // Make the output overlap, as it will be used to hold the masked
5036 // second input.
5037 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5038 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005039 break;
5040 }
5041 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005042 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005043 if (op->InputAt(1)->IsConstant()) {
5044 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
5045 // For simplicity, use kOutputOverlap even though we only require that low registers
5046 // don't clash with high registers which the register allocator currently guarantees.
5047 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5048 } else {
5049 locations->SetInAt(1, Location::RequiresRegister());
5050 locations->AddTemp(Location::RequiresRegister());
5051 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5052 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005053 break;
5054 }
5055 default:
5056 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
5057 }
5058}
5059
5060void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
5061 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
5062
5063 LocationSummary* locations = op->GetLocations();
5064 Location out = locations->Out();
5065 Location first = locations->InAt(0);
5066 Location second = locations->InAt(1);
5067
5068 Primitive::Type type = op->GetResultType();
5069 switch (type) {
5070 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005071 Register out_reg = out.AsRegister<Register>();
5072 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00005073 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005074 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00005075 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00005076 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00005077 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01005078 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00005079 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01005080 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00005081 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01005082 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00005083 }
5084 } else {
5085 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00005086 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00005087 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00005088 __ Mov(out_reg, first_reg);
5089 } else if (op->IsShl()) {
5090 __ Lsl(out_reg, first_reg, shift_value);
5091 } else if (op->IsShr()) {
5092 __ Asr(out_reg, first_reg, shift_value);
5093 } else {
5094 __ Lsr(out_reg, first_reg, shift_value);
5095 }
5096 }
5097 break;
5098 }
5099 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005100 Register o_h = out.AsRegisterPairHigh<Register>();
5101 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00005102
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005103 Register high = first.AsRegisterPairHigh<Register>();
5104 Register low = first.AsRegisterPairLow<Register>();
5105
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005106 if (second.IsRegister()) {
5107 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005108
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005109 Register second_reg = second.AsRegister<Register>();
5110
5111 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00005112 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005113 // Shift the high part
5114 __ Lsl(o_h, high, o_l);
5115 // Shift the low part and `or` what overflew on the high part
5116 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
5117 __ Lsr(temp, low, temp);
5118 __ orr(o_h, o_h, ShifterOperand(temp));
5119 // If the shift is > 32 bits, override the high part
5120 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
5121 __ it(PL);
5122 __ Lsl(o_h, low, temp, PL);
5123 // Shift the low part
5124 __ Lsl(o_l, low, o_l);
5125 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00005126 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005127 // Shift the low part
5128 __ Lsr(o_l, low, o_h);
5129 // Shift the high part and `or` what underflew on the low part
5130 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
5131 __ Lsl(temp, high, temp);
5132 __ orr(o_l, o_l, ShifterOperand(temp));
5133 // If the shift is > 32 bits, override the low part
5134 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
5135 __ it(PL);
5136 __ Asr(o_l, high, temp, PL);
5137 // Shift the high part
5138 __ Asr(o_h, high, o_h);
5139 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00005140 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005141 // same as Shr except we use `Lsr`s and not `Asr`s
5142 __ Lsr(o_l, low, o_h);
5143 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
5144 __ Lsl(temp, high, temp);
5145 __ orr(o_l, o_l, ShifterOperand(temp));
5146 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
5147 __ it(PL);
5148 __ Lsr(o_l, high, temp, PL);
5149 __ Lsr(o_h, high, o_h);
5150 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005151 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005152 // Register allocator doesn't create partial overlap.
5153 DCHECK_NE(o_l, high);
5154 DCHECK_NE(o_h, low);
5155 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00005156 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005157 if (shift_value > 32) {
5158 if (op->IsShl()) {
5159 __ Lsl(o_h, low, shift_value - 32);
5160 __ LoadImmediate(o_l, 0);
5161 } else if (op->IsShr()) {
5162 __ Asr(o_l, high, shift_value - 32);
5163 __ Asr(o_h, high, 31);
5164 } else {
5165 __ Lsr(o_l, high, shift_value - 32);
5166 __ LoadImmediate(o_h, 0);
5167 }
5168 } else if (shift_value == 32) {
5169 if (op->IsShl()) {
5170 __ mov(o_h, ShifterOperand(low));
5171 __ LoadImmediate(o_l, 0);
5172 } else if (op->IsShr()) {
5173 __ mov(o_l, ShifterOperand(high));
5174 __ Asr(o_h, high, 31);
5175 } else {
5176 __ mov(o_l, ShifterOperand(high));
5177 __ LoadImmediate(o_h, 0);
5178 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00005179 } else if (shift_value == 1) {
5180 if (op->IsShl()) {
5181 __ Lsls(o_l, low, 1);
5182 __ adc(o_h, high, ShifterOperand(high));
5183 } else if (op->IsShr()) {
5184 __ Asrs(o_h, high, 1);
5185 __ Rrx(o_l, low);
5186 } else {
5187 __ Lsrs(o_h, high, 1);
5188 __ Rrx(o_l, low);
5189 }
5190 } else {
5191 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005192 if (op->IsShl()) {
5193 __ Lsl(o_h, high, shift_value);
5194 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
5195 __ Lsl(o_l, low, shift_value);
5196 } else if (op->IsShr()) {
5197 __ Lsr(o_l, low, shift_value);
5198 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
5199 __ Asr(o_h, high, shift_value);
5200 } else {
5201 __ Lsr(o_l, low, shift_value);
5202 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
5203 __ Lsr(o_h, high, shift_value);
5204 }
5205 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005206 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005207 break;
5208 }
5209 default:
5210 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005211 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00005212 }
5213}
5214
5215void LocationsBuilderARM::VisitShl(HShl* shl) {
5216 HandleShift(shl);
5217}
5218
5219void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
5220 HandleShift(shl);
5221}
5222
5223void LocationsBuilderARM::VisitShr(HShr* shr) {
5224 HandleShift(shr);
5225}
5226
5227void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
5228 HandleShift(shr);
5229}
5230
5231void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
5232 HandleShift(ushr);
5233}
5234
5235void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
5236 HandleShift(ushr);
5237}
5238
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01005239void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005240 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005241 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
David Brazdil6de19382016-01-08 17:37:10 +00005242 if (instruction->IsStringAlloc()) {
5243 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
5244 } else {
5245 InvokeRuntimeCallingConvention calling_convention;
5246 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00005247 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005248 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01005249}
5250
5251void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01005252 // Note: if heap poisoning is enabled, the entry point takes cares
5253 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00005254 if (instruction->IsStringAlloc()) {
5255 // String is allocated through StringFactory. Call NewEmptyString entry point.
5256 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07005257 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00005258 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
5259 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
5260 __ blx(LR);
5261 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
5262 } else {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01005263 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00005264 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00005265 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01005266}
5267
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005268void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
5269 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005270 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005271 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005272 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00005273 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5274 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005275}
5276
5277void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01005278 // Note: if heap poisoning is enabled, the entry point takes cares
5279 // of poisoning the reference.
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00005280 QuickEntrypointEnum entrypoint =
5281 CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
5282 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00005283 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00005284 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005285}
5286
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005287void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005288 LocationSummary* locations =
5289 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01005290 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
5291 if (location.IsStackSlot()) {
5292 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5293 } else if (location.IsDoubleStackSlot()) {
5294 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005295 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01005296 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005297}
5298
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005299void InstructionCodeGeneratorARM::VisitParameterValue(
5300 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01005301 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005302}
5303
5304void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
5305 LocationSummary* locations =
5306 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5307 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
5308}
5309
5310void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
5311 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005312}
5313
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005314void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005315 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005316 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005317 locations->SetInAt(0, Location::RequiresRegister());
5318 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01005319}
5320
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005321void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
5322 LocationSummary* locations = not_->GetLocations();
5323 Location out = locations->Out();
5324 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00005325 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005326 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00005327 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005328 break;
5329
5330 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01005331 __ mvn(out.AsRegisterPairLow<Register>(),
5332 ShifterOperand(in.AsRegisterPairLow<Register>()));
5333 __ mvn(out.AsRegisterPairHigh<Register>(),
5334 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005335 break;
5336
5337 default:
5338 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
5339 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01005340}
5341
David Brazdil66d126e2015-04-03 16:02:44 +01005342void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
5343 LocationSummary* locations =
5344 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
5345 locations->SetInAt(0, Location::RequiresRegister());
5346 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5347}
5348
5349void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01005350 LocationSummary* locations = bool_not->GetLocations();
5351 Location out = locations->Out();
5352 Location in = locations->InAt(0);
5353 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
5354}
5355
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005356void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005357 LocationSummary* locations =
5358 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00005359 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00005360 case Primitive::kPrimBoolean:
5361 case Primitive::kPrimByte:
5362 case Primitive::kPrimShort:
5363 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08005364 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00005365 case Primitive::kPrimLong: {
5366 locations->SetInAt(0, Location::RequiresRegister());
5367 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005368 // Output overlaps because it is written before doing the low comparison.
5369 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00005370 break;
5371 }
5372 case Primitive::kPrimFloat:
5373 case Primitive::kPrimDouble: {
5374 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01005375 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00005376 locations->SetOut(Location::RequiresRegister());
5377 break;
5378 }
5379 default:
5380 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
5381 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005382}
5383
5384void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005385 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005386 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00005387 Location left = locations->InAt(0);
5388 Location right = locations->InAt(1);
5389
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005390 Label less, greater, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00005391 Label* final_label = codegen_->GetFinalLabel(compare, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00005392 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00005393 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00005394 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00005395 case Primitive::kPrimBoolean:
5396 case Primitive::kPrimByte:
5397 case Primitive::kPrimShort:
5398 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08005399 case Primitive::kPrimInt: {
5400 __ LoadImmediate(out, 0);
5401 __ cmp(left.AsRegister<Register>(),
5402 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
5403 less_cond = LT;
5404 break;
5405 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005406 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005407 __ cmp(left.AsRegisterPairHigh<Register>(),
5408 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005409 __ b(&less, LT);
5410 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01005411 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00005412 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005413 __ cmp(left.AsRegisterPairLow<Register>(),
5414 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00005415 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00005416 break;
5417 }
5418 case Primitive::kPrimFloat:
5419 case Primitive::kPrimDouble: {
5420 __ LoadImmediate(out, 0);
Donghui Bai426b49c2016-11-08 14:55:38 +08005421 GenerateVcmp(compare, codegen_);
Calin Juravleddb7df22014-11-25 20:56:51 +00005422 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00005423 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005424 break;
5425 }
5426 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00005427 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00005428 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005429 }
Aart Bika19616e2016-02-01 18:57:58 -08005430
Anton Kirilov6f644202017-02-27 18:29:45 +00005431 __ b(final_label, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00005432 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00005433
5434 __ Bind(&greater);
5435 __ LoadImmediate(out, 1);
Anton Kirilov6f644202017-02-27 18:29:45 +00005436 __ b(final_label);
Calin Juravleddb7df22014-11-25 20:56:51 +00005437
5438 __ Bind(&less);
5439 __ LoadImmediate(out, -1);
5440
Anton Kirilov6f644202017-02-27 18:29:45 +00005441 if (done.IsLinked()) {
5442 __ Bind(&done);
5443 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005444}
5445
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005446void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005447 LocationSummary* locations =
5448 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01005449 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01005450 locations->SetInAt(i, Location::Any());
5451 }
5452 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005453}
5454
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005455void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005456 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005457}
5458
Roland Levillainc9285912015-12-18 10:38:42 +00005459void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
5460 // TODO (ported from quick): revisit ARM barrier kinds.
5461 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00005462 switch (kind) {
5463 case MemBarrierKind::kAnyStore:
5464 case MemBarrierKind::kLoadAny:
5465 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005466 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00005467 break;
5468 }
5469 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005470 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00005471 break;
5472 }
5473 default:
5474 LOG(FATAL) << "Unexpected memory barrier " << kind;
5475 }
Kenny Root1d8199d2015-06-02 11:01:10 -07005476 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00005477}
5478
5479void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
5480 uint32_t offset,
5481 Register out_lo,
5482 Register out_hi) {
5483 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005484 // Ensure `out_lo` is different from `addr`, so that loading
5485 // `offset` into `out_lo` does not clutter `addr`.
5486 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00005487 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005488 __ add(IP, addr, ShifterOperand(out_lo));
5489 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005490 }
5491 __ ldrexd(out_lo, out_hi, addr);
5492}
5493
5494void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
5495 uint32_t offset,
5496 Register value_lo,
5497 Register value_hi,
5498 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00005499 Register temp2,
5500 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005501 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00005502 if (offset != 0) {
5503 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005504 __ add(IP, addr, ShifterOperand(temp1));
5505 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005506 }
5507 __ Bind(&fail);
5508 // We need a load followed by store. (The address used in a STREX instruction must
5509 // be the same as the address in the most recently executed LDREX instruction.)
5510 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00005511 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005512 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005513 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00005514}
5515
5516void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5517 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5518
Nicolas Geoffray39468442014-09-02 15:17:15 +01005519 LocationSummary* locations =
5520 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005521 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005522
Calin Juravle52c48962014-12-16 17:02:57 +00005523 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005524 if (Primitive::IsFloatingPointType(field_type)) {
5525 locations->SetInAt(1, Location::RequiresFpuRegister());
5526 } else {
5527 locations->SetInAt(1, Location::RequiresRegister());
5528 }
5529
Calin Juravle52c48962014-12-16 17:02:57 +00005530 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00005531 bool generate_volatile = field_info.IsVolatile()
5532 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005533 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01005534 bool needs_write_barrier =
5535 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005536 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00005537 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01005538 if (needs_write_barrier) {
5539 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005540 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005541 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005542 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005543 // - registers need to be consecutive
5544 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005545 // We don't test for ARM yet, and the assertion makes sure that we
5546 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005547 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5548
5549 locations->AddTemp(Location::RequiresRegister());
5550 locations->AddTemp(Location::RequiresRegister());
5551 if (field_type == Primitive::kPrimDouble) {
5552 // For doubles we need two more registers to copy the value.
5553 locations->AddTemp(Location::RegisterLocation(R2));
5554 locations->AddTemp(Location::RegisterLocation(R3));
5555 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005556 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005557}
5558
Calin Juravle52c48962014-12-16 17:02:57 +00005559void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005560 const FieldInfo& field_info,
5561 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00005562 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5563
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005564 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00005565 Register base = locations->InAt(0).AsRegister<Register>();
5566 Location value = locations->InAt(1);
5567
5568 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005569 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005570 Primitive::Type field_type = field_info.GetFieldType();
5571 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01005572 bool needs_write_barrier =
5573 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00005574
5575 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005576 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00005577 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005578
5579 switch (field_type) {
5580 case Primitive::kPrimBoolean:
5581 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00005582 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005583 break;
5584 }
5585
5586 case Primitive::kPrimShort:
5587 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00005588 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005589 break;
5590 }
5591
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005592 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005593 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01005594 if (kPoisonHeapReferences && needs_write_barrier) {
5595 // Note that in the case where `value` is a null reference,
5596 // we do not enter this block, as a null reference does not
5597 // need poisoning.
5598 DCHECK_EQ(field_type, Primitive::kPrimNot);
5599 Register temp = locations->GetTemp(0).AsRegister<Register>();
5600 __ Mov(temp, value.AsRegister<Register>());
5601 __ PoisonHeapReference(temp);
5602 __ StoreToOffset(kStoreWord, temp, base, offset);
5603 } else {
5604 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
5605 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005606 break;
5607 }
5608
5609 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00005610 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005611 GenerateWideAtomicStore(base, offset,
5612 value.AsRegisterPairLow<Register>(),
5613 value.AsRegisterPairHigh<Register>(),
5614 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005615 locations->GetTemp(1).AsRegister<Register>(),
5616 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005617 } else {
5618 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005619 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005620 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005621 break;
5622 }
5623
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005624 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00005625 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005626 break;
5627 }
5628
5629 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005630 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005631 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005632 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
5633 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
5634
5635 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
5636
5637 GenerateWideAtomicStore(base, offset,
5638 value_reg_lo,
5639 value_reg_hi,
5640 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005641 locations->GetTemp(3).AsRegister<Register>(),
5642 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005643 } else {
5644 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005645 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005646 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005647 break;
5648 }
5649
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005650 case Primitive::kPrimVoid:
5651 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005652 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005653 }
Calin Juravle52c48962014-12-16 17:02:57 +00005654
Calin Juravle77520bc2015-01-12 18:45:46 +00005655 // Longs and doubles are handled in the switch.
5656 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
5657 codegen_->MaybeRecordImplicitNullCheck(instruction);
5658 }
5659
5660 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
5661 Register temp = locations->GetTemp(0).AsRegister<Register>();
5662 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005663 codegen_->MarkGCCard(
5664 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00005665 }
5666
Calin Juravle52c48962014-12-16 17:02:57 +00005667 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005668 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00005669 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005670}
5671
Calin Juravle52c48962014-12-16 17:02:57 +00005672void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
5673 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00005674
5675 bool object_field_get_with_read_barrier =
5676 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005677 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00005678 new (GetGraph()->GetArena()) LocationSummary(instruction,
5679 object_field_get_with_read_barrier ?
5680 LocationSummary::kCallOnSlowPath :
5681 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005682 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005683 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005684 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005685 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00005686
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005687 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00005688 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005689 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00005690 // The output overlaps in case of volatile long: we don't want the
5691 // code generated by GenerateWideAtomicLoad to overwrite the
5692 // object's location. Likewise, in the case of an object field get
5693 // with read barriers enabled, we do not want the load to overwrite
5694 // the object's location, as we need it to emit the read barrier.
5695 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
5696 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01005697
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005698 if (Primitive::IsFloatingPointType(instruction->GetType())) {
5699 locations->SetOut(Location::RequiresFpuRegister());
5700 } else {
5701 locations->SetOut(Location::RequiresRegister(),
5702 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
5703 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005704 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00005705 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005706 // - registers need to be consecutive
5707 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005708 // We don't test for ARM yet, and the assertion makes sure that we
5709 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005710 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5711 locations->AddTemp(Location::RequiresRegister());
5712 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00005713 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
5714 // We need a temporary register for the read barrier marking slow
5715 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01005716 if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
5717 !Runtime::Current()->UseJitCompilation()) {
5718 // If link-time thunks for the Baker read barrier are enabled, for AOT
5719 // loads we need a temporary only if the offset is too big.
5720 if (field_info.GetFieldOffset().Uint32Value() >= kReferenceLoadMinFarOffset) {
5721 locations->AddTemp(Location::RequiresRegister());
5722 }
5723 // And we always need the reserved entrypoint register.
5724 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
5725 } else {
5726 locations->AddTemp(Location::RequiresRegister());
5727 }
Calin Juravle52c48962014-12-16 17:02:57 +00005728 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005729}
5730
Vladimir Marko37dd80d2016-08-01 17:41:45 +01005731Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
5732 DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
5733 << input->GetType();
5734 if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
5735 (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
5736 return Location::ConstantLocation(input->AsConstant());
5737 } else {
5738 return Location::RequiresFpuRegister();
5739 }
5740}
5741
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005742Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
5743 Opcode opcode) {
5744 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
5745 if (constant->IsConstant() &&
5746 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
5747 return Location::ConstantLocation(constant->AsConstant());
5748 }
5749 return Location::RequiresRegister();
5750}
5751
5752bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
5753 Opcode opcode) {
5754 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
5755 if (Primitive::Is64BitType(input_cst->GetType())) {
Vladimir Marko59751a72016-08-05 14:37:27 +01005756 Opcode high_opcode = opcode;
5757 SetCc low_set_cc = kCcDontCare;
5758 switch (opcode) {
5759 case SUB:
5760 // Flip the operation to an ADD.
5761 value = -value;
5762 opcode = ADD;
5763 FALLTHROUGH_INTENDED;
5764 case ADD:
5765 if (Low32Bits(value) == 0u) {
5766 return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
5767 }
5768 high_opcode = ADC;
5769 low_set_cc = kCcSet;
5770 break;
5771 default:
5772 break;
5773 }
5774 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
5775 CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005776 } else {
5777 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
5778 }
5779}
5780
Vladimir Marko59751a72016-08-05 14:37:27 +01005781bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
5782 Opcode opcode,
5783 SetCc set_cc) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005784 ShifterOperand so;
5785 ArmAssembler* assembler = codegen_->GetAssembler();
Vladimir Marko59751a72016-08-05 14:37:27 +01005786 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005787 return true;
5788 }
5789 Opcode neg_opcode = kNoOperand;
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005790 uint32_t neg_value = 0;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005791 switch (opcode) {
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005792 case AND: neg_opcode = BIC; neg_value = ~value; break;
5793 case ORR: neg_opcode = ORN; neg_value = ~value; break;
5794 case ADD: neg_opcode = SUB; neg_value = -value; break;
5795 case ADC: neg_opcode = SBC; neg_value = ~value; break;
5796 case SUB: neg_opcode = ADD; neg_value = -value; break;
5797 case SBC: neg_opcode = ADC; neg_value = ~value; break;
5798 case MOV: neg_opcode = MVN; neg_value = ~value; break;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005799 default:
5800 return false;
5801 }
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005802
5803 if (assembler->ShifterOperandCanHold(kNoRegister,
5804 kNoRegister,
5805 neg_opcode,
5806 neg_value,
5807 set_cc,
5808 &so)) {
5809 return true;
5810 }
5811
5812 return opcode == AND && IsPowerOfTwo(value + 1);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005813}
5814
Calin Juravle52c48962014-12-16 17:02:57 +00005815void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
5816 const FieldInfo& field_info) {
5817 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005818
Calin Juravle52c48962014-12-16 17:02:57 +00005819 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005820 Location base_loc = locations->InAt(0);
5821 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00005822 Location out = locations->Out();
5823 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005824 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005825 Primitive::Type field_type = field_info.GetFieldType();
5826 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5827
5828 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00005829 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00005830 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005831 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005832
Roland Levillainc9285912015-12-18 10:38:42 +00005833 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00005834 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005835 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005836
Roland Levillainc9285912015-12-18 10:38:42 +00005837 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00005838 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005839 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005840
Roland Levillainc9285912015-12-18 10:38:42 +00005841 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00005842 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005843 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005844
5845 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00005846 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005847 break;
Roland Levillainc9285912015-12-18 10:38:42 +00005848
5849 case Primitive::kPrimNot: {
5850 // /* HeapReference<Object> */ out = *(base + offset)
5851 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5852 Location temp_loc = locations->GetTemp(0);
5853 // Note that a potential implicit null check is handled in this
5854 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
5855 codegen_->GenerateFieldLoadWithBakerReadBarrier(
5856 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
5857 if (is_volatile) {
5858 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5859 }
5860 } else {
5861 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
5862 codegen_->MaybeRecordImplicitNullCheck(instruction);
5863 if (is_volatile) {
5864 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5865 }
5866 // If read barriers are enabled, emit read barriers other than
5867 // Baker's using a slow path (and also unpoison the loaded
5868 // reference, if heap poisoning is enabled).
5869 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
5870 }
5871 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005872 }
5873
Roland Levillainc9285912015-12-18 10:38:42 +00005874 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00005875 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005876 GenerateWideAtomicLoad(base, offset,
5877 out.AsRegisterPairLow<Register>(),
5878 out.AsRegisterPairHigh<Register>());
5879 } else {
5880 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
5881 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005882 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005883
Roland Levillainc9285912015-12-18 10:38:42 +00005884 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00005885 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005886 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005887
5888 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005889 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005890 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005891 Register lo = locations->GetTemp(0).AsRegister<Register>();
5892 Register hi = locations->GetTemp(1).AsRegister<Register>();
5893 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00005894 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005895 __ vmovdrr(out_reg, lo, hi);
5896 } else {
5897 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005898 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005899 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005900 break;
5901 }
5902
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005903 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00005904 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005905 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005906 }
Calin Juravle52c48962014-12-16 17:02:57 +00005907
Roland Levillainc9285912015-12-18 10:38:42 +00005908 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
5909 // Potential implicit null checks, in the case of reference or
5910 // double fields, are handled in the previous switch statement.
5911 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00005912 codegen_->MaybeRecordImplicitNullCheck(instruction);
5913 }
5914
Calin Juravle52c48962014-12-16 17:02:57 +00005915 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005916 if (field_type == Primitive::kPrimNot) {
5917 // Memory barriers, in the case of references, are also handled
5918 // in the previous switch statement.
5919 } else {
5920 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5921 }
Roland Levillain4d027112015-07-01 15:41:14 +01005922 }
Calin Juravle52c48962014-12-16 17:02:57 +00005923}
5924
5925void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
5926 HandleFieldSet(instruction, instruction->GetFieldInfo());
5927}
5928
5929void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005930 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00005931}
5932
5933void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5934 HandleFieldGet(instruction, instruction->GetFieldInfo());
5935}
5936
5937void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5938 HandleFieldGet(instruction, instruction->GetFieldInfo());
5939}
5940
5941void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5942 HandleFieldGet(instruction, instruction->GetFieldInfo());
5943}
5944
5945void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5946 HandleFieldGet(instruction, instruction->GetFieldInfo());
5947}
5948
5949void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5950 HandleFieldSet(instruction, instruction->GetFieldInfo());
5951}
5952
5953void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005954 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005955}
5956
Calin Juravlee460d1d2015-09-29 04:52:17 +01005957void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
5958 HUnresolvedInstanceFieldGet* instruction) {
5959 FieldAccessCallingConventionARM calling_convention;
5960 codegen_->CreateUnresolvedFieldLocationSummary(
5961 instruction, instruction->GetFieldType(), calling_convention);
5962}
5963
5964void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
5965 HUnresolvedInstanceFieldGet* instruction) {
5966 FieldAccessCallingConventionARM calling_convention;
5967 codegen_->GenerateUnresolvedFieldAccess(instruction,
5968 instruction->GetFieldType(),
5969 instruction->GetFieldIndex(),
5970 instruction->GetDexPc(),
5971 calling_convention);
5972}
5973
5974void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
5975 HUnresolvedInstanceFieldSet* instruction) {
5976 FieldAccessCallingConventionARM calling_convention;
5977 codegen_->CreateUnresolvedFieldLocationSummary(
5978 instruction, instruction->GetFieldType(), calling_convention);
5979}
5980
5981void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
5982 HUnresolvedInstanceFieldSet* instruction) {
5983 FieldAccessCallingConventionARM calling_convention;
5984 codegen_->GenerateUnresolvedFieldAccess(instruction,
5985 instruction->GetFieldType(),
5986 instruction->GetFieldIndex(),
5987 instruction->GetDexPc(),
5988 calling_convention);
5989}
5990
5991void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
5992 HUnresolvedStaticFieldGet* instruction) {
5993 FieldAccessCallingConventionARM calling_convention;
5994 codegen_->CreateUnresolvedFieldLocationSummary(
5995 instruction, instruction->GetFieldType(), calling_convention);
5996}
5997
5998void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
5999 HUnresolvedStaticFieldGet* instruction) {
6000 FieldAccessCallingConventionARM calling_convention;
6001 codegen_->GenerateUnresolvedFieldAccess(instruction,
6002 instruction->GetFieldType(),
6003 instruction->GetFieldIndex(),
6004 instruction->GetDexPc(),
6005 calling_convention);
6006}
6007
6008void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
6009 HUnresolvedStaticFieldSet* instruction) {
6010 FieldAccessCallingConventionARM calling_convention;
6011 codegen_->CreateUnresolvedFieldLocationSummary(
6012 instruction, instruction->GetFieldType(), calling_convention);
6013}
6014
6015void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
6016 HUnresolvedStaticFieldSet* instruction) {
6017 FieldAccessCallingConventionARM calling_convention;
6018 codegen_->GenerateUnresolvedFieldAccess(instruction,
6019 instruction->GetFieldType(),
6020 instruction->GetFieldIndex(),
6021 instruction->GetDexPc(),
6022 calling_convention);
6023}
6024
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006025void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006026 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
6027 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006028}
6029
Calin Juravle2ae48182016-03-16 14:05:09 +00006030void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
6031 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00006032 return;
6033 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006034 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00006035
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006036 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00006037 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006038}
6039
Calin Juravle2ae48182016-03-16 14:05:09 +00006040void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01006041 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00006042 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006043
6044 LocationSummary* locations = instruction->GetLocations();
6045 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006046
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006047 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01006048}
6049
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006050void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00006051 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00006052}
6053
Artem Serov6c916792016-07-11 14:02:34 +01006054static LoadOperandType GetLoadOperandType(Primitive::Type type) {
6055 switch (type) {
6056 case Primitive::kPrimNot:
6057 return kLoadWord;
6058 case Primitive::kPrimBoolean:
6059 return kLoadUnsignedByte;
6060 case Primitive::kPrimByte:
6061 return kLoadSignedByte;
6062 case Primitive::kPrimChar:
6063 return kLoadUnsignedHalfword;
6064 case Primitive::kPrimShort:
6065 return kLoadSignedHalfword;
6066 case Primitive::kPrimInt:
6067 return kLoadWord;
6068 case Primitive::kPrimLong:
6069 return kLoadWordPair;
6070 case Primitive::kPrimFloat:
6071 return kLoadSWord;
6072 case Primitive::kPrimDouble:
6073 return kLoadDWord;
6074 default:
6075 LOG(FATAL) << "Unreachable type " << type;
6076 UNREACHABLE();
6077 }
6078}
6079
6080static StoreOperandType GetStoreOperandType(Primitive::Type type) {
6081 switch (type) {
6082 case Primitive::kPrimNot:
6083 return kStoreWord;
6084 case Primitive::kPrimBoolean:
6085 case Primitive::kPrimByte:
6086 return kStoreByte;
6087 case Primitive::kPrimChar:
6088 case Primitive::kPrimShort:
6089 return kStoreHalfword;
6090 case Primitive::kPrimInt:
6091 return kStoreWord;
6092 case Primitive::kPrimLong:
6093 return kStoreWordPair;
6094 case Primitive::kPrimFloat:
6095 return kStoreSWord;
6096 case Primitive::kPrimDouble:
6097 return kStoreDWord;
6098 default:
6099 LOG(FATAL) << "Unreachable type " << type;
6100 UNREACHABLE();
6101 }
6102}
6103
6104void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
6105 Location out_loc,
6106 Register base,
6107 Register reg_offset,
6108 Condition cond) {
6109 uint32_t shift_count = Primitive::ComponentSizeShift(type);
6110 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
6111
6112 switch (type) {
6113 case Primitive::kPrimByte:
6114 __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
6115 break;
6116 case Primitive::kPrimBoolean:
6117 __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
6118 break;
6119 case Primitive::kPrimShort:
6120 __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
6121 break;
6122 case Primitive::kPrimChar:
6123 __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
6124 break;
6125 case Primitive::kPrimNot:
6126 case Primitive::kPrimInt:
6127 __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
6128 break;
6129 // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
6130 case Primitive::kPrimLong:
6131 case Primitive::kPrimFloat:
6132 case Primitive::kPrimDouble:
6133 default:
6134 LOG(FATAL) << "Unreachable type " << type;
6135 UNREACHABLE();
6136 }
6137}
6138
6139void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
6140 Location loc,
6141 Register base,
6142 Register reg_offset,
6143 Condition cond) {
6144 uint32_t shift_count = Primitive::ComponentSizeShift(type);
6145 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
6146
6147 switch (type) {
6148 case Primitive::kPrimByte:
6149 case Primitive::kPrimBoolean:
6150 __ strb(loc.AsRegister<Register>(), mem_address, cond);
6151 break;
6152 case Primitive::kPrimShort:
6153 case Primitive::kPrimChar:
6154 __ strh(loc.AsRegister<Register>(), mem_address, cond);
6155 break;
6156 case Primitive::kPrimNot:
6157 case Primitive::kPrimInt:
6158 __ str(loc.AsRegister<Register>(), mem_address, cond);
6159 break;
6160 // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
6161 case Primitive::kPrimLong:
6162 case Primitive::kPrimFloat:
6163 case Primitive::kPrimDouble:
6164 default:
6165 LOG(FATAL) << "Unreachable type " << type;
6166 UNREACHABLE();
6167 }
6168}
6169
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006170void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006171 bool object_array_get_with_read_barrier =
6172 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01006173 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00006174 new (GetGraph()->GetArena()) LocationSummary(instruction,
6175 object_array_get_with_read_barrier ?
6176 LocationSummary::kCallOnSlowPath :
6177 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01006178 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006179 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006180 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006181 locations->SetInAt(0, Location::RequiresRegister());
6182 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01006183 if (Primitive::IsFloatingPointType(instruction->GetType())) {
6184 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6185 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00006186 // The output overlaps in the case of an object array get with
6187 // read barriers enabled: we do not want the move to overwrite the
6188 // array's location, as we need it to emit the read barrier.
6189 locations->SetOut(
6190 Location::RequiresRegister(),
6191 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01006192 }
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01006193 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
6194 // We need a temporary register for the read barrier marking slow
6195 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
6196 if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
6197 !Runtime::Current()->UseJitCompilation() &&
6198 instruction->GetIndex()->IsConstant()) {
6199 // Array loads with constant index are treated as field loads.
6200 // If link-time thunks for the Baker read barrier are enabled, for AOT
6201 // constant index loads we need a temporary only if the offset is too big.
6202 uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
6203 uint32_t index = instruction->GetIndex()->AsIntConstant()->GetValue();
6204 offset += index << Primitive::ComponentSizeShift(Primitive::kPrimNot);
6205 if (offset >= kReferenceLoadMinFarOffset) {
6206 locations->AddTemp(Location::RequiresRegister());
6207 }
6208 // And we always need the reserved entrypoint register.
6209 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
6210 } else if (kBakerReadBarrierLinkTimeThunksEnableForArrays &&
6211 !Runtime::Current()->UseJitCompilation() &&
6212 !instruction->GetIndex()->IsConstant()) {
6213 // We need a non-scratch temporary for the array data pointer.
6214 locations->AddTemp(Location::RequiresRegister());
6215 // And we always need the reserved entrypoint register.
6216 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
6217 } else {
6218 locations->AddTemp(Location::RequiresRegister());
6219 }
6220 } else if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
6221 // Also need a temporary for String compression feature.
Roland Levillainc9285912015-12-18 10:38:42 +00006222 locations->AddTemp(Location::RequiresRegister());
6223 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006224}
6225
6226void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
6227 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006228 Location obj_loc = locations->InAt(0);
6229 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006230 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00006231 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01006232 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Roland Levillainc9285912015-12-18 10:38:42 +00006233 Primitive::Type type = instruction->GetType();
jessicahandojo05765752016-09-09 19:01:32 -07006234 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
6235 instruction->IsStringCharAt();
Artem Serov328429f2016-07-06 16:23:04 +01006236 HInstruction* array_instr = instruction->GetArray();
6237 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Artem Serov6c916792016-07-11 14:02:34 +01006238
Roland Levillain4d027112015-07-01 15:41:14 +01006239 switch (type) {
Artem Serov6c916792016-07-11 14:02:34 +01006240 case Primitive::kPrimBoolean:
6241 case Primitive::kPrimByte:
6242 case Primitive::kPrimShort:
6243 case Primitive::kPrimChar:
Roland Levillainc9285912015-12-18 10:38:42 +00006244 case Primitive::kPrimInt: {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006245 Register length;
6246 if (maybe_compressed_char_at) {
6247 length = locations->GetTemp(0).AsRegister<Register>();
6248 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
6249 __ LoadFromOffset(kLoadWord, length, obj, count_offset);
6250 codegen_->MaybeRecordImplicitNullCheck(instruction);
6251 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006252 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01006253 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
jessicahandojo05765752016-09-09 19:01:32 -07006254 if (maybe_compressed_char_at) {
jessicahandojo05765752016-09-09 19:01:32 -07006255 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006256 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006257 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
6258 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
6259 "Expecting 0=compressed, 1=uncompressed");
6260 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07006261 __ LoadFromOffset(kLoadUnsignedByte,
6262 out_loc.AsRegister<Register>(),
6263 obj,
6264 data_offset + const_index);
Anton Kirilov6f644202017-02-27 18:29:45 +00006265 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07006266 __ Bind(&uncompressed_load);
6267 __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
6268 out_loc.AsRegister<Register>(),
6269 obj,
6270 data_offset + (const_index << 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00006271 if (done.IsLinked()) {
6272 __ Bind(&done);
6273 }
jessicahandojo05765752016-09-09 19:01:32 -07006274 } else {
6275 uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
Artem Serov6c916792016-07-11 14:02:34 +01006276
jessicahandojo05765752016-09-09 19:01:32 -07006277 LoadOperandType load_type = GetLoadOperandType(type);
6278 __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
6279 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006280 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006281 Register temp = IP;
6282
6283 if (has_intermediate_address) {
6284 // We do not need to compute the intermediate address from the array: the
6285 // input instruction has done it already. See the comment in
6286 // `TryExtractArrayAccessAddress()`.
6287 if (kIsDebugBuild) {
6288 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6289 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
6290 }
6291 temp = obj;
6292 } else {
6293 __ add(temp, obj, ShifterOperand(data_offset));
6294 }
jessicahandojo05765752016-09-09 19:01:32 -07006295 if (maybe_compressed_char_at) {
6296 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006297 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006298 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
6299 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
6300 "Expecting 0=compressed, 1=uncompressed");
6301 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07006302 __ ldrb(out_loc.AsRegister<Register>(),
6303 Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
Anton Kirilov6f644202017-02-27 18:29:45 +00006304 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07006305 __ Bind(&uncompressed_load);
6306 __ ldrh(out_loc.AsRegister<Register>(),
6307 Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00006308 if (done.IsLinked()) {
6309 __ Bind(&done);
6310 }
jessicahandojo05765752016-09-09 19:01:32 -07006311 } else {
6312 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
6313 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006314 }
6315 break;
6316 }
6317
Roland Levillainc9285912015-12-18 10:38:42 +00006318 case Primitive::kPrimNot: {
Roland Levillain19c54192016-11-04 13:44:09 +00006319 // The read barrier instrumentation of object ArrayGet
6320 // instructions does not support the HIntermediateAddress
6321 // instruction.
6322 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
6323
Roland Levillainc9285912015-12-18 10:38:42 +00006324 static_assert(
6325 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6326 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006327 // /* HeapReference<Object> */ out =
6328 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
6329 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
6330 Location temp = locations->GetTemp(0);
6331 // Note that a potential implicit null check is handled in this
6332 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01006333 DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
6334 if (index.IsConstant()) {
6335 // Array load with a constant index can be treated as a field load.
6336 data_offset += helpers::Int32ConstantFrom(index) << Primitive::ComponentSizeShift(type);
6337 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6338 out_loc,
6339 obj,
6340 data_offset,
6341 locations->GetTemp(0),
6342 /* needs_null_check */ false);
6343 } else {
6344 codegen_->GenerateArrayLoadWithBakerReadBarrier(
6345 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ false);
6346 }
Roland Levillainc9285912015-12-18 10:38:42 +00006347 } else {
6348 Register out = out_loc.AsRegister<Register>();
6349 if (index.IsConstant()) {
6350 size_t offset =
6351 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6352 __ LoadFromOffset(kLoadWord, out, obj, offset);
6353 codegen_->MaybeRecordImplicitNullCheck(instruction);
6354 // If read barriers are enabled, emit read barriers other than
6355 // Baker's using a slow path (and also unpoison the loaded
6356 // reference, if heap poisoning is enabled).
6357 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
6358 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006359 Register temp = IP;
6360
6361 if (has_intermediate_address) {
6362 // We do not need to compute the intermediate address from the array: the
6363 // input instruction has done it already. See the comment in
6364 // `TryExtractArrayAccessAddress()`.
6365 if (kIsDebugBuild) {
6366 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6367 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
6368 }
6369 temp = obj;
6370 } else {
6371 __ add(temp, obj, ShifterOperand(data_offset));
6372 }
6373 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Artem Serov6c916792016-07-11 14:02:34 +01006374
Roland Levillainc9285912015-12-18 10:38:42 +00006375 codegen_->MaybeRecordImplicitNullCheck(instruction);
6376 // If read barriers are enabled, emit read barriers other than
6377 // Baker's using a slow path (and also unpoison the loaded
6378 // reference, if heap poisoning is enabled).
6379 codegen_->MaybeGenerateReadBarrierSlow(
6380 instruction, out_loc, out_loc, obj_loc, data_offset, index);
6381 }
6382 }
6383 break;
6384 }
6385
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006386 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006387 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006388 size_t offset =
6389 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006390 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006391 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006392 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00006393 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006394 }
6395 break;
6396 }
6397
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006398 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00006399 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006400 if (index.IsConstant()) {
6401 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006402 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006403 } else {
6404 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00006405 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006406 }
6407 break;
6408 }
6409
6410 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00006411 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006412 if (index.IsConstant()) {
6413 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006414 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006415 } else {
6416 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00006417 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006418 }
6419 break;
6420 }
6421
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006422 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01006423 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07006424 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006425 }
Roland Levillain4d027112015-07-01 15:41:14 +01006426
6427 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00006428 // Potential implicit null checks, in the case of reference
6429 // arrays, are handled in the previous switch statement.
jessicahandojo05765752016-09-09 19:01:32 -07006430 } else if (!maybe_compressed_char_at) {
Roland Levillainc9285912015-12-18 10:38:42 +00006431 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01006432 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006433}
6434
6435void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01006436 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006437
6438 bool needs_write_barrier =
6439 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00006440 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006441
Nicolas Geoffray39468442014-09-02 15:17:15 +01006442 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006443 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01006444 may_need_runtime_call_for_type_check ?
Roland Levillain3b359c72015-11-17 19:35:12 +00006445 LocationSummary::kCallOnSlowPath :
6446 LocationSummary::kNoCall);
6447
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006448 locations->SetInAt(0, Location::RequiresRegister());
6449 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6450 if (Primitive::IsFloatingPointType(value_type)) {
6451 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006452 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006453 locations->SetInAt(2, Location::RequiresRegister());
6454 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006455 if (needs_write_barrier) {
6456 // Temporary registers for the write barrier.
6457 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00006458 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006459 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006460}
6461
6462void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
6463 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006464 Location array_loc = locations->InAt(0);
6465 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006466 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01006467 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00006468 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006469 bool needs_write_barrier =
6470 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Artem Serov6c916792016-07-11 14:02:34 +01006471 uint32_t data_offset =
6472 mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
6473 Location value_loc = locations->InAt(2);
Artem Serov328429f2016-07-06 16:23:04 +01006474 HInstruction* array_instr = instruction->GetArray();
6475 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006476
6477 switch (value_type) {
6478 case Primitive::kPrimBoolean:
Artem Serov6c916792016-07-11 14:02:34 +01006479 case Primitive::kPrimByte:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006480 case Primitive::kPrimShort:
Artem Serov6c916792016-07-11 14:02:34 +01006481 case Primitive::kPrimChar:
6482 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006483 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01006484 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
6485 uint32_t full_offset =
6486 data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
6487 StoreOperandType store_type = GetStoreOperandType(value_type);
6488 __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006489 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006490 Register temp = IP;
6491
6492 if (has_intermediate_address) {
6493 // We do not need to compute the intermediate address from the array: the
6494 // input instruction has done it already. See the comment in
6495 // `TryExtractArrayAccessAddress()`.
6496 if (kIsDebugBuild) {
6497 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6498 DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
6499 }
6500 temp = array;
6501 } else {
6502 __ add(temp, array, ShifterOperand(data_offset));
6503 }
Artem Serov6c916792016-07-11 14:02:34 +01006504 codegen_->StoreToShiftedRegOffset(value_type,
6505 value_loc,
Artem Serov328429f2016-07-06 16:23:04 +01006506 temp,
Artem Serov6c916792016-07-11 14:02:34 +01006507 index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006508 }
6509 break;
6510 }
6511
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006512 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00006513 Register value = value_loc.AsRegister<Register>();
Artem Serov328429f2016-07-06 16:23:04 +01006514 // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
6515 // See the comment in instruction_simplifier_shared.cc.
6516 DCHECK(!has_intermediate_address);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006517
6518 if (instruction->InputAt(2)->IsNullConstant()) {
6519 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006520 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006521 size_t offset =
6522 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Artem Serov6c916792016-07-11 14:02:34 +01006523 __ StoreToOffset(kStoreWord, value, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006524 } else {
6525 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006526 __ add(IP, array, ShifterOperand(data_offset));
6527 codegen_->StoreToShiftedRegOffset(value_type,
6528 value_loc,
6529 IP,
6530 index.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006531 }
Roland Levillain1407ee72016-01-08 15:56:19 +00006532 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00006533 DCHECK(!needs_write_barrier);
6534 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006535 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006536 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006537
6538 DCHECK(needs_write_barrier);
Roland Levillain16d9f942016-08-25 17:27:56 +01006539 Location temp1_loc = locations->GetTemp(0);
6540 Register temp1 = temp1_loc.AsRegister<Register>();
6541 Location temp2_loc = locations->GetTemp(1);
6542 Register temp2 = temp2_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006543 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6544 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6545 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6546 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006547 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01006548 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006549
Roland Levillain3b359c72015-11-17 19:35:12 +00006550 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006551 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
6552 codegen_->AddSlowPath(slow_path);
6553 if (instruction->GetValueCanBeNull()) {
6554 Label non_zero;
6555 __ CompareAndBranchIfNonZero(value, &non_zero);
6556 if (index.IsConstant()) {
6557 size_t offset =
6558 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6559 __ StoreToOffset(kStoreWord, value, array, offset);
6560 } else {
6561 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006562 __ add(IP, array, ShifterOperand(data_offset));
6563 codegen_->StoreToShiftedRegOffset(value_type,
6564 value_loc,
6565 IP,
6566 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006567 }
6568 codegen_->MaybeRecordImplicitNullCheck(instruction);
Anton Kirilov6f644202017-02-27 18:29:45 +00006569 __ b(final_label);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006570 __ Bind(&non_zero);
6571 }
6572
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006573 // Note that when read barriers are enabled, the type checks
6574 // are performed without read barriers. This is fine, even in
6575 // the case where a class object is in the from-space after
6576 // the flip, as a comparison involving such a type would not
6577 // produce a false positive; it may of course produce a false
6578 // negative, in which case we would take the ArraySet slow
6579 // path.
Roland Levillain16d9f942016-08-25 17:27:56 +01006580
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006581 // /* HeapReference<Class> */ temp1 = array->klass_
6582 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
6583 codegen_->MaybeRecordImplicitNullCheck(instruction);
6584 __ MaybeUnpoisonHeapReference(temp1);
Roland Levillain16d9f942016-08-25 17:27:56 +01006585
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006586 // /* HeapReference<Class> */ temp1 = temp1->component_type_
6587 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
6588 // /* HeapReference<Class> */ temp2 = value->klass_
6589 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
6590 // If heap poisoning is enabled, no need to unpoison `temp1`
6591 // nor `temp2`, as we are comparing two poisoned references.
6592 __ cmp(temp1, ShifterOperand(temp2));
Roland Levillain16d9f942016-08-25 17:27:56 +01006593
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006594 if (instruction->StaticTypeOfArrayIsObjectArray()) {
6595 Label do_put;
6596 __ b(&do_put, EQ);
6597 // If heap poisoning is enabled, the `temp1` reference has
6598 // not been unpoisoned yet; unpoison it now.
Roland Levillain3b359c72015-11-17 19:35:12 +00006599 __ MaybeUnpoisonHeapReference(temp1);
6600
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006601 // /* HeapReference<Class> */ temp1 = temp1->super_class_
6602 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
6603 // If heap poisoning is enabled, no need to unpoison
6604 // `temp1`, as we are comparing against null below.
6605 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
6606 __ Bind(&do_put);
6607 } else {
6608 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006609 }
6610 }
6611
Artem Serov6c916792016-07-11 14:02:34 +01006612 Register source = value;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006613 if (kPoisonHeapReferences) {
6614 // Note that in the case where `value` is a null reference,
6615 // we do not enter this block, as a null reference does not
6616 // need poisoning.
6617 DCHECK_EQ(value_type, Primitive::kPrimNot);
6618 __ Mov(temp1, value);
6619 __ PoisonHeapReference(temp1);
6620 source = temp1;
6621 }
6622
6623 if (index.IsConstant()) {
6624 size_t offset =
6625 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6626 __ StoreToOffset(kStoreWord, source, array, offset);
6627 } else {
6628 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006629
6630 __ add(IP, array, ShifterOperand(data_offset));
6631 codegen_->StoreToShiftedRegOffset(value_type,
6632 Location::RegisterLocation(source),
6633 IP,
6634 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006635 }
6636
Roland Levillain3b359c72015-11-17 19:35:12 +00006637 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006638 codegen_->MaybeRecordImplicitNullCheck(instruction);
6639 }
6640
6641 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
6642
6643 if (done.IsLinked()) {
6644 __ Bind(&done);
6645 }
6646
6647 if (slow_path != nullptr) {
6648 __ Bind(slow_path->GetExitLabel());
6649 }
6650
6651 break;
6652 }
6653
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006654 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006655 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006656 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006657 size_t offset =
6658 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006659 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006660 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006661 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006662 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006663 }
6664 break;
6665 }
6666
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006667 case Primitive::kPrimFloat: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006668 Location value = locations->InAt(2);
6669 DCHECK(value.IsFpuRegister());
6670 if (index.IsConstant()) {
6671 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006672 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006673 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006674 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006675 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
6676 }
6677 break;
6678 }
6679
6680 case Primitive::kPrimDouble: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006681 Location value = locations->InAt(2);
6682 DCHECK(value.IsFpuRegisterPair());
6683 if (index.IsConstant()) {
6684 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006685 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006686 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006687 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006688 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
6689 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006690
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006691 break;
6692 }
6693
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006694 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006695 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07006696 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006697 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006698
Roland Levillain80e67092016-01-08 16:04:55 +00006699 // Objects are handled in the switch.
6700 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00006701 codegen_->MaybeRecordImplicitNullCheck(instruction);
6702 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006703}
6704
6705void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01006706 LocationSummary* locations =
6707 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006708 locations->SetInAt(0, Location::RequiresRegister());
6709 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006710}
6711
6712void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
6713 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01006714 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00006715 Register obj = locations->InAt(0).AsRegister<Register>();
6716 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006717 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00006718 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo05765752016-09-09 19:01:32 -07006719 // Mask out compression flag from String's array length.
6720 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006721 __ Lsr(out, out, 1u);
jessicahandojo05765752016-09-09 19:01:32 -07006722 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006723}
6724
Artem Serov328429f2016-07-06 16:23:04 +01006725void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
Artem Serov328429f2016-07-06 16:23:04 +01006726 LocationSummary* locations =
6727 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6728
6729 locations->SetInAt(0, Location::RequiresRegister());
6730 locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
6731 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6732}
6733
6734void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
6735 LocationSummary* locations = instruction->GetLocations();
6736 Location out = locations->Out();
6737 Location first = locations->InAt(0);
6738 Location second = locations->InAt(1);
6739
Artem Serov328429f2016-07-06 16:23:04 +01006740 if (second.IsRegister()) {
6741 __ add(out.AsRegister<Register>(),
6742 first.AsRegister<Register>(),
6743 ShifterOperand(second.AsRegister<Register>()));
6744 } else {
6745 __ AddConstant(out.AsRegister<Register>(),
6746 first.AsRegister<Register>(),
6747 second.GetConstant()->AsIntConstant()->GetValue());
6748 }
6749}
6750
Artem Serove1811ed2017-04-27 16:50:47 +01006751void LocationsBuilderARM::VisitIntermediateAddressIndex(HIntermediateAddressIndex* instruction) {
6752 LOG(FATAL) << "Unreachable " << instruction->GetId();
6753}
6754
6755void InstructionCodeGeneratorARM::VisitIntermediateAddressIndex(
6756 HIntermediateAddressIndex* instruction) {
6757 LOG(FATAL) << "Unreachable " << instruction->GetId();
6758}
6759
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006760void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006761 RegisterSet caller_saves = RegisterSet::Empty();
6762 InvokeRuntimeCallingConvention calling_convention;
6763 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6764 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
6765 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Artem Serov2dd053d2017-03-08 14:54:06 +00006766
6767 HInstruction* index = instruction->InputAt(0);
6768 HInstruction* length = instruction->InputAt(1);
6769 // If both index and length are constants we can statically check the bounds. But if at least one
6770 // of them is not encodable ArmEncodableConstantOrRegister will create
6771 // Location::RequiresRegister() which is not desired to happen. Instead we create constant
6772 // locations.
6773 bool both_const = index->IsConstant() && length->IsConstant();
6774 locations->SetInAt(0, both_const
6775 ? Location::ConstantLocation(index->AsConstant())
6776 : ArmEncodableConstantOrRegister(index, CMP));
6777 locations->SetInAt(1, both_const
6778 ? Location::ConstantLocation(length->AsConstant())
6779 : ArmEncodableConstantOrRegister(length, CMP));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006780}
6781
6782void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
6783 LocationSummary* locations = instruction->GetLocations();
Artem Serov2dd053d2017-03-08 14:54:06 +00006784 Location index_loc = locations->InAt(0);
6785 Location length_loc = locations->InAt(1);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006786
Artem Serov2dd053d2017-03-08 14:54:06 +00006787 if (length_loc.IsConstant()) {
6788 int32_t length = helpers::Int32ConstantFrom(length_loc);
6789 if (index_loc.IsConstant()) {
6790 // BCE will remove the bounds check if we are guaranteed to pass.
6791 int32_t index = helpers::Int32ConstantFrom(index_loc);
6792 if (index < 0 || index >= length) {
6793 SlowPathCodeARM* slow_path =
6794 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6795 codegen_->AddSlowPath(slow_path);
6796 __ b(slow_path->GetEntryLabel());
6797 } else {
6798 // Some optimization after BCE may have generated this, and we should not
6799 // generate a bounds check if it is a valid range.
6800 }
6801 return;
6802 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006803
Artem Serov2dd053d2017-03-08 14:54:06 +00006804 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6805 __ cmp(index_loc.AsRegister<Register>(), ShifterOperand(length));
6806 codegen_->AddSlowPath(slow_path);
6807 __ b(slow_path->GetEntryLabel(), HS);
6808 } else {
6809 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6810 if (index_loc.IsConstant()) {
6811 int32_t index = helpers::Int32ConstantFrom(index_loc);
6812 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index));
6813 } else {
6814 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index_loc.AsRegister<Register>()));
6815 }
6816 codegen_->AddSlowPath(slow_path);
6817 __ b(slow_path->GetEntryLabel(), LS);
6818 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006819}
6820
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006821void CodeGeneratorARM::MarkGCCard(Register temp,
6822 Register card,
6823 Register object,
6824 Register value,
6825 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00006826 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006827 if (can_be_null) {
6828 __ CompareAndBranchIfZero(value, &is_null);
6829 }
Andreas Gampe542451c2016-07-26 09:02:02 -07006830 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006831 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
6832 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006833 if (can_be_null) {
6834 __ Bind(&is_null);
6835 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006836}
6837
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006838void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006839 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006840}
6841
6842void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006843 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6844}
6845
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006846void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01006847 LocationSummary* locations =
6848 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01006849 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006850}
6851
6852void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006853 HBasicBlock* block = instruction->GetBlock();
6854 if (block->GetLoopInformation() != nullptr) {
6855 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6856 // The back edge will generate the suspend check.
6857 return;
6858 }
6859 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6860 // The goto will generate the suspend check.
6861 return;
6862 }
6863 GenerateSuspendCheck(instruction, nullptr);
6864}
6865
6866void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
6867 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006868 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01006869 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
6870 if (slow_path == nullptr) {
6871 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
6872 instruction->SetSlowPath(slow_path);
6873 codegen_->AddSlowPath(slow_path);
6874 if (successor != nullptr) {
6875 DCHECK(successor->IsLoopHeader());
6876 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
6877 }
6878 } else {
6879 DCHECK_EQ(slow_path->GetSuccessor(), successor);
6880 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006881
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00006882 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07006883 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006884 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006885 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006886 __ Bind(slow_path->GetReturnLabel());
6887 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006888 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006889 __ b(slow_path->GetEntryLabel());
6890 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006891}
6892
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006893ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
6894 return codegen_->GetAssembler();
6895}
6896
6897void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006898 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006899 Location source = move->GetSource();
6900 Location destination = move->GetDestination();
6901
6902 if (source.IsRegister()) {
6903 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006904 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006905 } else if (destination.IsFpuRegister()) {
6906 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006907 } else {
6908 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006909 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006910 SP, destination.GetStackIndex());
6911 }
6912 } else if (source.IsStackSlot()) {
6913 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006914 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006915 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006916 } else if (destination.IsFpuRegister()) {
6917 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006918 } else {
6919 DCHECK(destination.IsStackSlot());
6920 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
6921 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6922 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006923 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006924 if (destination.IsRegister()) {
6925 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
6926 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006927 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006928 } else {
6929 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006930 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
6931 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006932 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006933 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006934 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
6935 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006936 } else if (destination.IsRegisterPair()) {
6937 DCHECK(ExpectedPairLayout(destination));
6938 __ LoadFromOffset(
6939 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
6940 } else {
6941 DCHECK(destination.IsFpuRegisterPair()) << destination;
6942 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6943 SP,
6944 source.GetStackIndex());
6945 }
6946 } else if (source.IsRegisterPair()) {
6947 if (destination.IsRegisterPair()) {
6948 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
6949 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006950 } else if (destination.IsFpuRegisterPair()) {
6951 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6952 source.AsRegisterPairLow<Register>(),
6953 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006954 } else {
6955 DCHECK(destination.IsDoubleStackSlot()) << destination;
6956 DCHECK(ExpectedPairLayout(source));
6957 __ StoreToOffset(
6958 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
6959 }
6960 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006961 if (destination.IsRegisterPair()) {
6962 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6963 destination.AsRegisterPairHigh<Register>(),
6964 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6965 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006966 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6967 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6968 } else {
6969 DCHECK(destination.IsDoubleStackSlot()) << destination;
6970 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
6971 SP,
6972 destination.GetStackIndex());
6973 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006974 } else {
6975 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00006976 HConstant* constant = source.GetConstant();
6977 if (constant->IsIntConstant() || constant->IsNullConstant()) {
6978 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006979 if (destination.IsRegister()) {
6980 __ LoadImmediate(destination.AsRegister<Register>(), value);
6981 } else {
6982 DCHECK(destination.IsStackSlot());
6983 __ LoadImmediate(IP, value);
6984 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6985 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006986 } else if (constant->IsLongConstant()) {
6987 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006988 if (destination.IsRegisterPair()) {
6989 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
6990 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006991 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006992 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006993 __ LoadImmediate(IP, Low32Bits(value));
6994 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6995 __ LoadImmediate(IP, High32Bits(value));
6996 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6997 }
6998 } else if (constant->IsDoubleConstant()) {
6999 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007000 if (destination.IsFpuRegisterPair()) {
7001 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00007002 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007003 DCHECK(destination.IsDoubleStackSlot()) << destination;
7004 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00007005 __ LoadImmediate(IP, Low32Bits(int_value));
7006 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
7007 __ LoadImmediate(IP, High32Bits(int_value));
7008 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
7009 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00007010 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00007011 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00007012 float value = constant->AsFloatConstant()->GetValue();
7013 if (destination.IsFpuRegister()) {
7014 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
7015 } else {
7016 DCHECK(destination.IsStackSlot());
7017 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
7018 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
7019 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01007020 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01007021 }
7022}
7023
7024void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
7025 __ Mov(IP, reg);
7026 __ LoadFromOffset(kLoadWord, reg, SP, mem);
7027 __ StoreToOffset(kStoreWord, IP, SP, mem);
7028}
7029
7030void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
7031 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
7032 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
7033 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
7034 SP, mem1 + stack_offset);
7035 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
7036 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
7037 SP, mem2 + stack_offset);
7038 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
7039}
7040
7041void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01007042 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01007043 Location source = move->GetSource();
7044 Location destination = move->GetDestination();
7045
7046 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00007047 DCHECK_NE(source.AsRegister<Register>(), IP);
7048 DCHECK_NE(destination.AsRegister<Register>(), IP);
7049 __ Mov(IP, source.AsRegister<Register>());
7050 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
7051 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01007052 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00007053 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01007054 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00007055 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01007056 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
7057 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00007058 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00007059 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00007060 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00007061 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007062 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007063 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007064 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007065 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007066 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
7067 destination.AsRegisterPairHigh<Register>(),
7068 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007069 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007070 Register low_reg = source.IsRegisterPair()
7071 ? source.AsRegisterPairLow<Register>()
7072 : destination.AsRegisterPairLow<Register>();
7073 int mem = source.IsRegisterPair()
7074 ? destination.GetStackIndex()
7075 : source.GetStackIndex();
7076 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007077 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007078 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007079 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007080 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007081 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
7082 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007083 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007084 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007085 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007086 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
7087 DRegister reg = source.IsFpuRegisterPair()
7088 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
7089 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
7090 int mem = source.IsFpuRegisterPair()
7091 ? destination.GetStackIndex()
7092 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007093 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007094 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00007095 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00007096 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
7097 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
7098 : destination.AsFpuRegister<SRegister>();
7099 int mem = source.IsFpuRegister()
7100 ? destination.GetStackIndex()
7101 : source.GetStackIndex();
7102
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00007103 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00007104 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00007105 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00007106 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00007107 Exchange(source.GetStackIndex(), destination.GetStackIndex());
7108 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01007109 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00007110 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01007111 }
7112}
7113
7114void ParallelMoveResolverARM::SpillScratch(int reg) {
7115 __ Push(static_cast<Register>(reg));
7116}
7117
7118void ParallelMoveResolverARM::RestoreScratch(int reg) {
7119 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01007120}
7121
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007122HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
7123 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007124 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007125 case HLoadClass::LoadKind::kInvalid:
7126 LOG(FATAL) << "UNREACHABLE";
7127 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007128 case HLoadClass::LoadKind::kReferrersClass:
7129 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007130 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007131 case HLoadClass::LoadKind::kBssEntry:
7132 DCHECK(!Runtime::Current()->UseJitCompilation());
7133 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007134 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007135 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007136 break;
Vladimir Marko764d4542017-05-16 10:31:41 +01007137 case HLoadClass::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007138 case HLoadClass::LoadKind::kRuntimeCall:
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007139 break;
7140 }
7141 return desired_class_load_kind;
7142}
7143
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007144void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00007145 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007146 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007147 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00007148 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007149 cls,
7150 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00007151 Location::RegisterLocation(R0));
Vladimir Markoea4c1262017-02-06 19:59:33 +00007152 DCHECK_EQ(calling_convention.GetRegisterAt(0), R0);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007153 return;
7154 }
Vladimir Marko41559982017-01-06 14:04:23 +00007155 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007156
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007157 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
7158 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007159 ? LocationSummary::kCallOnSlowPath
7160 : LocationSummary::kNoCall;
7161 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007162 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007163 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007164 }
7165
Vladimir Marko41559982017-01-06 14:04:23 +00007166 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007167 locations->SetInAt(0, Location::RequiresRegister());
7168 }
7169 locations->SetOut(Location::RequiresRegister());
Vladimir Markoea4c1262017-02-06 19:59:33 +00007170 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
7171 if (!kUseReadBarrier || kUseBakerReadBarrier) {
7172 // Rely on the type resolution or initialization and marking to save everything we need.
7173 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
7174 // to the custom calling convention) or by marking, so we request a different temp.
7175 locations->AddTemp(Location::RequiresRegister());
7176 RegisterSet caller_saves = RegisterSet::Empty();
7177 InvokeRuntimeCallingConvention calling_convention;
7178 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7179 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
7180 // that the the kPrimNot result register is the same as the first argument register.
7181 locations->SetCustomSlowPathCallerSaves(caller_saves);
7182 } else {
7183 // For non-Baker read barrier we have a temp-clobbering call.
7184 }
7185 }
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01007186 if (kUseBakerReadBarrier && kBakerReadBarrierLinkTimeThunksEnableForGcRoots) {
7187 if (load_kind == HLoadClass::LoadKind::kBssEntry ||
7188 (load_kind == HLoadClass::LoadKind::kReferrersClass &&
7189 !Runtime::Current()->UseJitCompilation())) {
7190 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
7191 }
7192 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007193}
7194
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007195// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7196// move.
7197void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00007198 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007199 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Marko41559982017-01-06 14:04:23 +00007200 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01007201 return;
7202 }
Vladimir Marko41559982017-01-06 14:04:23 +00007203 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01007204
Vladimir Marko41559982017-01-06 14:04:23 +00007205 LocationSummary* locations = cls->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007206 Location out_loc = locations->Out();
7207 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007208
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007209 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
7210 ? kWithoutReadBarrier
7211 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007212 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00007213 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007214 case HLoadClass::LoadKind::kReferrersClass: {
7215 DCHECK(!cls->CanCallRuntime());
7216 DCHECK(!cls->MustGenerateClinitCheck());
7217 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
7218 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007219 GenerateGcRootFieldLoad(cls,
7220 out_loc,
7221 current_method,
7222 ArtMethod::DeclaringClassOffset().Int32Value(),
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007223 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007224 break;
7225 }
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007226 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007227 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007228 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007229 CodeGeneratorARM::PcRelativePatchInfo* labels =
7230 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
7231 __ BindTrackedLabel(&labels->movw_label);
7232 __ movw(out, /* placeholder */ 0u);
7233 __ BindTrackedLabel(&labels->movt_label);
7234 __ movt(out, /* placeholder */ 0u);
7235 __ BindTrackedLabel(&labels->add_pc_label);
7236 __ add(out, out, ShifterOperand(PC));
7237 break;
7238 }
7239 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007240 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007241 uint32_t address = dchecked_integral_cast<uint32_t>(
7242 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
7243 DCHECK_NE(address, 0u);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007244 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
7245 break;
7246 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007247 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Markoea4c1262017-02-06 19:59:33 +00007248 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
7249 ? locations->GetTemp(0).AsRegister<Register>()
7250 : out;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007251 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko1998cd02017-01-13 13:02:58 +00007252 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007253 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00007254 __ movw(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007255 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00007256 __ movt(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007257 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00007258 __ add(temp, temp, ShifterOperand(PC));
7259 GenerateGcRootFieldLoad(cls, out_loc, temp, /* offset */ 0, read_barrier_option);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007260 generate_null_check = true;
7261 break;
7262 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007263 case HLoadClass::LoadKind::kJitTableAddress: {
7264 __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
7265 cls->GetTypeIndex(),
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007266 cls->GetClass()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007267 // /* GcRoot<mirror::Class> */ out = *out
Vladimir Markoea4c1262017-02-06 19:59:33 +00007268 GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007269 break;
7270 }
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007271 case HLoadClass::LoadKind::kRuntimeCall:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007272 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00007273 LOG(FATAL) << "UNREACHABLE";
7274 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007275 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007276
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007277 if (generate_null_check || cls->MustGenerateClinitCheck()) {
7278 DCHECK(cls->CanCallRuntime());
Artem Serovf4d6aee2016-07-11 10:41:45 +01007279 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007280 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
7281 codegen_->AddSlowPath(slow_path);
7282 if (generate_null_check) {
7283 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
7284 }
7285 if (cls->MustGenerateClinitCheck()) {
7286 GenerateClassInitializationCheck(slow_path, out);
7287 } else {
7288 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007289 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007290 }
7291}
7292
7293void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
7294 LocationSummary* locations =
7295 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
7296 locations->SetInAt(0, Location::RequiresRegister());
7297 if (check->HasUses()) {
7298 locations->SetOut(Location::SameAsFirstInput());
7299 }
7300}
7301
7302void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007303 // We assume the class is not null.
Artem Serovf4d6aee2016-07-11 10:41:45 +01007304 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007305 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007306 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00007307 GenerateClassInitializationCheck(slow_path,
7308 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007309}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007310
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007311void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Artem Serovf4d6aee2016-07-11 10:41:45 +01007312 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007313 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
7314 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
7315 __ b(slow_path->GetEntryLabel(), LT);
7316 // Even if the initialized flag is set, we may be in a situation where caches are not synced
7317 // properly. Therefore, we do a memory fence.
7318 __ dmb(ISH);
7319 __ Bind(slow_path->GetExitLabel());
7320}
7321
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007322HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
7323 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007324 switch (desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007325 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoaad75c62016-10-03 08:46:48 +00007326 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01007327 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007328 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007329 case HLoadString::LoadKind::kJitTableAddress:
7330 DCHECK(Runtime::Current()->UseJitCompilation());
7331 break;
Vladimir Marko764d4542017-05-16 10:31:41 +01007332 case HLoadString::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007333 case HLoadString::LoadKind::kRuntimeCall:
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007334 break;
7335 }
7336 return desired_string_load_kind;
7337}
7338
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007339void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007340 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00007341 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007342 HLoadString::LoadKind load_kind = load->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007343 if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007344 locations->SetOut(Location::RegisterLocation(R0));
7345 } else {
7346 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007347 if (load_kind == HLoadString::LoadKind::kBssEntry) {
7348 if (!kUseReadBarrier || kUseBakerReadBarrier) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00007349 // Rely on the pResolveString and marking to save everything we need, including temps.
7350 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
7351 // to the custom calling convention) or by marking, so we request a different temp.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007352 locations->AddTemp(Location::RequiresRegister());
7353 RegisterSet caller_saves = RegisterSet::Empty();
7354 InvokeRuntimeCallingConvention calling_convention;
7355 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7356 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
7357 // that the the kPrimNot result register is the same as the first argument register.
7358 locations->SetCustomSlowPathCallerSaves(caller_saves);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01007359 if (kUseBakerReadBarrier && kBakerReadBarrierLinkTimeThunksEnableForGcRoots) {
7360 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
7361 }
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007362 } else {
7363 // For non-Baker read barrier we have a temp-clobbering call.
7364 }
7365 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007366 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007367}
7368
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007369// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7370// move.
7371void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01007372 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007373 Location out_loc = locations->Out();
7374 Register out = out_loc.AsRegister<Register>();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007375 HLoadString::LoadKind load_kind = load->GetLoadKind();
Roland Levillain3b359c72015-11-17 19:35:12 +00007376
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007377 switch (load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007378 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00007379 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007380 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007381 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007382 __ BindTrackedLabel(&labels->movw_label);
7383 __ movw(out, /* placeholder */ 0u);
7384 __ BindTrackedLabel(&labels->movt_label);
7385 __ movt(out, /* placeholder */ 0u);
7386 __ BindTrackedLabel(&labels->add_pc_label);
7387 __ add(out, out, ShifterOperand(PC));
7388 return; // No dex cache slow path.
7389 }
7390 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007391 uint32_t address = dchecked_integral_cast<uint32_t>(
7392 reinterpret_cast<uintptr_t>(load->GetString().Get()));
7393 DCHECK_NE(address, 0u);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007394 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
7395 return; // No dex cache slow path.
7396 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00007397 case HLoadString::LoadKind::kBssEntry: {
7398 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markoea4c1262017-02-06 19:59:33 +00007399 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
7400 ? locations->GetTemp(0).AsRegister<Register>()
7401 : out;
Vladimir Markoaad75c62016-10-03 08:46:48 +00007402 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007403 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markoaad75c62016-10-03 08:46:48 +00007404 __ BindTrackedLabel(&labels->movw_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007405 __ movw(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007406 __ BindTrackedLabel(&labels->movt_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007407 __ movt(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007408 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007409 __ add(temp, temp, ShifterOperand(PC));
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007410 GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007411 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
7412 codegen_->AddSlowPath(slow_path);
7413 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
7414 __ Bind(slow_path->GetExitLabel());
7415 return;
7416 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007417 case HLoadString::LoadKind::kJitTableAddress: {
7418 __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007419 load->GetStringIndex(),
7420 load->GetString()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007421 // /* GcRoot<mirror::String> */ out = *out
7422 GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
7423 return;
7424 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007425 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07007426 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007427 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007428
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007429 // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007430 DCHECK(load_kind == HLoadString::LoadKind::kRuntimeCall);
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007431 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007432 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007433 __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007434 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
7435 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007436}
7437
David Brazdilcb1c0552015-08-04 16:22:25 +01007438static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07007439 return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
David Brazdilcb1c0552015-08-04 16:22:25 +01007440}
7441
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007442void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
7443 LocationSummary* locations =
7444 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
7445 locations->SetOut(Location::RequiresRegister());
7446}
7447
7448void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00007449 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01007450 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
7451}
7452
7453void LocationsBuilderARM::VisitClearException(HClearException* clear) {
7454 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
7455}
7456
7457void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007458 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01007459 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007460}
7461
7462void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
7463 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01007464 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007465 InvokeRuntimeCallingConvention calling_convention;
7466 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7467}
7468
7469void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01007470 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007471 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007472}
7473
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007474// Temp is used for read barrier.
7475static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
7476 if (kEmitCompilerReadBarrier &&
7477 (kUseBakerReadBarrier ||
7478 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7479 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7480 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
7481 return 1;
7482 }
7483 return 0;
7484}
7485
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007486// Interface case has 3 temps, one for holding the number of interfaces, one for the current
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007487// interface pointer, one for loading the current interface.
7488// The other checks have one temp for loading the object's class.
7489static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
7490 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7491 return 3;
7492 }
7493 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Roland Levillainc9285912015-12-18 10:38:42 +00007494}
7495
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007496void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007497 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00007498 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01007499 bool baker_read_barrier_slow_path = false;
Roland Levillain3b359c72015-11-17 19:35:12 +00007500 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007501 case TypeCheckKind::kExactCheck:
7502 case TypeCheckKind::kAbstractClassCheck:
7503 case TypeCheckKind::kClassHierarchyCheck:
7504 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007505 call_kind =
7506 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01007507 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007508 break;
7509 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007510 case TypeCheckKind::kUnresolvedCheck:
7511 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007512 call_kind = LocationSummary::kCallOnSlowPath;
7513 break;
7514 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007515
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007516 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01007517 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007518 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007519 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007520 locations->SetInAt(0, Location::RequiresRegister());
7521 locations->SetInAt(1, Location::RequiresRegister());
7522 // The "out" register is used as a temporary, so it overlaps with the inputs.
7523 // Note that TypeCheckSlowPathARM uses this register too.
7524 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007525 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01007526 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
7527 codegen_->MaybeAddBakerCcEntrypointTempForFields(locations);
7528 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007529}
7530
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007531void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007532 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007533 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007534 Location obj_loc = locations->InAt(0);
7535 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007536 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007537 Location out_loc = locations->Out();
7538 Register out = out_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007539 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7540 DCHECK_LE(num_temps, 1u);
7541 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007542 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007543 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7544 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7545 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007546 Label done;
7547 Label* const final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01007548 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007549
7550 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007551 // avoid null check if we know obj is not null.
7552 if (instruction->MustDoNullCheck()) {
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007553 DCHECK_NE(out, obj);
7554 __ LoadImmediate(out, 0);
7555 __ CompareAndBranchIfZero(obj, final_label);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007556 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007557
Roland Levillainc9285912015-12-18 10:38:42 +00007558 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007559 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007560 // /* HeapReference<Class> */ out = obj->klass_
7561 GenerateReferenceLoadTwoRegisters(instruction,
7562 out_loc,
7563 obj_loc,
7564 class_offset,
7565 maybe_temp_loc,
7566 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007567 // Classes must be equal for the instanceof to succeed.
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007568 __ cmp(out, ShifterOperand(cls));
7569 // We speculatively set the result to false without changing the condition
7570 // flags, which allows us to avoid some branching later.
7571 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7572
7573 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7574 // we check that the output is in a low register, so that a 16-bit MOV
7575 // encoding can be used.
7576 if (ArmAssembler::IsLowRegister(out)) {
7577 __ it(EQ);
7578 __ mov(out, ShifterOperand(1), EQ);
7579 } else {
7580 __ b(final_label, NE);
7581 __ LoadImmediate(out, 1);
7582 }
7583
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007584 break;
7585 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007586
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007587 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007588 // /* HeapReference<Class> */ out = obj->klass_
7589 GenerateReferenceLoadTwoRegisters(instruction,
7590 out_loc,
7591 obj_loc,
7592 class_offset,
7593 maybe_temp_loc,
7594 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007595 // If the class is abstract, we eagerly fetch the super class of the
7596 // object to avoid doing a comparison we know will fail.
7597 Label loop;
7598 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007599 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007600 GenerateReferenceLoadOneRegister(instruction,
7601 out_loc,
7602 super_offset,
7603 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007604 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007605 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007606 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007607 __ cmp(out, ShifterOperand(cls));
7608 __ b(&loop, NE);
7609 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007610 break;
7611 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007612
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007613 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007614 // /* HeapReference<Class> */ out = obj->klass_
7615 GenerateReferenceLoadTwoRegisters(instruction,
7616 out_loc,
7617 obj_loc,
7618 class_offset,
7619 maybe_temp_loc,
7620 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007621 // Walk over the class hierarchy to find a match.
7622 Label loop, success;
7623 __ Bind(&loop);
7624 __ cmp(out, ShifterOperand(cls));
7625 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007626 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007627 GenerateReferenceLoadOneRegister(instruction,
7628 out_loc,
7629 super_offset,
7630 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007631 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007632 // This is essentially a null check, but it sets the condition flags to the
7633 // proper value for the code that follows the loop, i.e. not `EQ`.
7634 __ cmp(out, ShifterOperand(1));
7635 __ b(&loop, HS);
7636
7637 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7638 // we check that the output is in a low register, so that a 16-bit MOV
7639 // encoding can be used.
7640 if (ArmAssembler::IsLowRegister(out)) {
7641 // If `out` is null, we use it for the result, and the condition flags
7642 // have already been set to `NE`, so the IT block that comes afterwards
7643 // (and which handles the successful case) turns into a NOP (instead of
7644 // overwriting `out`).
7645 __ Bind(&success);
7646 // There is only one branch to the `success` label (which is bound to this
7647 // IT block), and it has the same condition, `EQ`, so in that case the MOV
7648 // is executed.
7649 __ it(EQ);
7650 __ mov(out, ShifterOperand(1), EQ);
7651 } else {
7652 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007653 __ b(final_label);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007654 __ Bind(&success);
7655 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007656 }
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007657
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007658 break;
7659 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007660
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007661 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007662 // /* HeapReference<Class> */ out = obj->klass_
7663 GenerateReferenceLoadTwoRegisters(instruction,
7664 out_loc,
7665 obj_loc,
7666 class_offset,
7667 maybe_temp_loc,
7668 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007669 // Do an exact check.
7670 Label exact_check;
7671 __ cmp(out, ShifterOperand(cls));
7672 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007673 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007674 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007675 GenerateReferenceLoadOneRegister(instruction,
7676 out_loc,
7677 component_offset,
7678 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007679 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007680 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007681 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007682 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
7683 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007684 __ cmp(out, ShifterOperand(0));
7685 // We speculatively set the result to false without changing the condition
7686 // flags, which allows us to avoid some branching later.
7687 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7688
7689 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7690 // we check that the output is in a low register, so that a 16-bit MOV
7691 // encoding can be used.
7692 if (ArmAssembler::IsLowRegister(out)) {
7693 __ Bind(&exact_check);
7694 __ it(EQ);
7695 __ mov(out, ShifterOperand(1), EQ);
7696 } else {
7697 __ b(final_label, NE);
7698 __ Bind(&exact_check);
7699 __ LoadImmediate(out, 1);
7700 }
7701
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007702 break;
7703 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007704
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007705 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007706 // No read barrier since the slow path will retry upon failure.
7707 // /* HeapReference<Class> */ out = obj->klass_
7708 GenerateReferenceLoadTwoRegisters(instruction,
7709 out_loc,
7710 obj_loc,
7711 class_offset,
7712 maybe_temp_loc,
7713 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007714 __ cmp(out, ShifterOperand(cls));
7715 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00007716 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7717 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007718 codegen_->AddSlowPath(slow_path);
7719 __ b(slow_path->GetEntryLabel(), NE);
7720 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007721 break;
7722 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007723
Calin Juravle98893e12015-10-02 21:05:03 +01007724 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007725 case TypeCheckKind::kInterfaceCheck: {
7726 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007727 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00007728 // cases.
7729 //
7730 // We cannot directly call the InstanceofNonTrivial runtime
7731 // entry point without resorting to a type checking slow path
7732 // here (i.e. by calling InvokeRuntime directly), as it would
7733 // require to assign fixed registers for the inputs of this
7734 // HInstanceOf instruction (following the runtime calling
7735 // convention), which might be cluttered by the potential first
7736 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00007737 //
7738 // TODO: Introduce a new runtime entry point taking the object
7739 // to test (instead of its class) as argument, and let it deal
7740 // with the read barrier issues. This will let us refactor this
7741 // case of the `switch` code as it was previously (with a direct
7742 // call to the runtime not using a type checking slow path).
7743 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00007744 DCHECK(locations->OnlyCallsOnSlowPath());
7745 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7746 /* is_fatal */ false);
7747 codegen_->AddSlowPath(slow_path);
7748 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007749 break;
7750 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007751 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007752
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007753 if (done.IsLinked()) {
7754 __ Bind(&done);
7755 }
7756
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007757 if (slow_path != nullptr) {
7758 __ Bind(slow_path->GetExitLabel());
7759 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007760}
7761
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007762void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007763 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7764 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
7765
Roland Levillain3b359c72015-11-17 19:35:12 +00007766 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7767 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007768 case TypeCheckKind::kExactCheck:
7769 case TypeCheckKind::kAbstractClassCheck:
7770 case TypeCheckKind::kClassHierarchyCheck:
7771 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007772 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
7773 LocationSummary::kCallOnSlowPath :
7774 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007775 break;
7776 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007777 case TypeCheckKind::kUnresolvedCheck:
7778 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007779 call_kind = LocationSummary::kCallOnSlowPath;
7780 break;
7781 }
7782
Roland Levillain3b359c72015-11-17 19:35:12 +00007783 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
7784 locations->SetInAt(0, Location::RequiresRegister());
7785 locations->SetInAt(1, Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007786 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007787}
7788
7789void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007790 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007791 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007792 Location obj_loc = locations->InAt(0);
7793 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007794 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007795 Location temp_loc = locations->GetTemp(0);
7796 Register temp = temp_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007797 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
7798 DCHECK_LE(num_temps, 3u);
7799 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
7800 Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
7801 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7802 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7803 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7804 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7805 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
7806 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
7807 const uint32_t object_array_data_offset =
7808 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007809
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007810 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
7811 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
7812 // read barriers is done for performance and code size reasons.
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007813 bool is_type_check_slow_path_fatal = false;
7814 if (!kEmitCompilerReadBarrier) {
7815 is_type_check_slow_path_fatal =
7816 (type_check_kind == TypeCheckKind::kExactCheck ||
7817 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7818 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7819 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
7820 !instruction->CanThrowIntoCatchBlock();
7821 }
Artem Serovf4d6aee2016-07-11 10:41:45 +01007822 SlowPathCodeARM* type_check_slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00007823 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7824 is_type_check_slow_path_fatal);
7825 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007826
7827 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00007828 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007829 // Avoid null check if we know obj is not null.
7830 if (instruction->MustDoNullCheck()) {
Anton Kirilov6f644202017-02-27 18:29:45 +00007831 __ CompareAndBranchIfZero(obj, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007832 }
7833
Roland Levillain3b359c72015-11-17 19:35:12 +00007834 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007835 case TypeCheckKind::kExactCheck:
7836 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007837 // /* HeapReference<Class> */ temp = obj->klass_
7838 GenerateReferenceLoadTwoRegisters(instruction,
7839 temp_loc,
7840 obj_loc,
7841 class_offset,
7842 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007843 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007844
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007845 __ cmp(temp, ShifterOperand(cls));
7846 // Jump to slow path for throwing the exception or doing a
7847 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00007848 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007849 break;
7850 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007851
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007852 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007853 // /* HeapReference<Class> */ temp = obj->klass_
7854 GenerateReferenceLoadTwoRegisters(instruction,
7855 temp_loc,
7856 obj_loc,
7857 class_offset,
7858 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007859 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007860
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007861 // If the class is abstract, we eagerly fetch the super class of the
7862 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007863 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007864 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007865 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007866 GenerateReferenceLoadOneRegister(instruction,
7867 temp_loc,
7868 super_offset,
7869 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007870 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007871
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007872 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7873 // exception.
7874 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
Roland Levillain3b359c72015-11-17 19:35:12 +00007875
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007876 // Otherwise, compare the classes.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007877 __ cmp(temp, ShifterOperand(cls));
7878 __ b(&loop, NE);
7879 break;
7880 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007881
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007882 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007883 // /* HeapReference<Class> */ temp = obj->klass_
7884 GenerateReferenceLoadTwoRegisters(instruction,
7885 temp_loc,
7886 obj_loc,
7887 class_offset,
7888 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007889 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007890
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007891 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007892 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007893 __ Bind(&loop);
7894 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007895 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007896
Roland Levillain3b359c72015-11-17 19:35:12 +00007897 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007898 GenerateReferenceLoadOneRegister(instruction,
7899 temp_loc,
7900 super_offset,
7901 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007902 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007903
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007904 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7905 // exception.
7906 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7907 // Otherwise, jump to the beginning of the loop.
7908 __ b(&loop);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007909 break;
7910 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007911
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007912 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007913 // /* HeapReference<Class> */ temp = obj->klass_
7914 GenerateReferenceLoadTwoRegisters(instruction,
7915 temp_loc,
7916 obj_loc,
7917 class_offset,
7918 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007919 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007920
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007921 // Do an exact check.
7922 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007923 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007924
7925 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007926 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007927 GenerateReferenceLoadOneRegister(instruction,
7928 temp_loc,
7929 component_offset,
7930 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007931 kWithoutReadBarrier);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007932 // If the component type is null, jump to the slow path to throw the exception.
7933 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7934 // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
7935 // to further check that this component type is not a primitive type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007936 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00007937 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007938 __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007939 break;
7940 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007941
Calin Juravle98893e12015-10-02 21:05:03 +01007942 case TypeCheckKind::kUnresolvedCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007943 // We always go into the type check slow path for the unresolved check case.
Roland Levillain3b359c72015-11-17 19:35:12 +00007944 // We cannot directly call the CheckCast runtime entry point
7945 // without resorting to a type checking slow path here (i.e. by
7946 // calling InvokeRuntime directly), as it would require to
7947 // assign fixed registers for the inputs of this HInstanceOf
7948 // instruction (following the runtime calling convention), which
7949 // might be cluttered by the potential first read barrier
7950 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007951
Roland Levillain3b359c72015-11-17 19:35:12 +00007952 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007953 break;
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007954
7955 case TypeCheckKind::kInterfaceCheck: {
7956 // Avoid read barriers to improve performance of the fast path. We can not get false
7957 // positives by doing this.
7958 // /* HeapReference<Class> */ temp = obj->klass_
7959 GenerateReferenceLoadTwoRegisters(instruction,
7960 temp_loc,
7961 obj_loc,
7962 class_offset,
7963 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007964 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007965
7966 // /* HeapReference<Class> */ temp = temp->iftable_
7967 GenerateReferenceLoadTwoRegisters(instruction,
7968 temp_loc,
7969 temp_loc,
7970 iftable_offset,
7971 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007972 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08007973 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007974 __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08007975 // Loop through the iftable and check if any class matches.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007976 Label start_loop;
7977 __ Bind(&start_loop);
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007978 __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
7979 type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007980 __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
7981 __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007982 // Go to next interface.
7983 __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
7984 __ sub(maybe_temp2_loc.AsRegister<Register>(),
7985 maybe_temp2_loc.AsRegister<Register>(),
7986 ShifterOperand(2));
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007987 // Compare the classes and continue the loop if they do not match.
7988 __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
7989 __ b(&start_loop, NE);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007990 break;
7991 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007992 }
Anton Kirilov6f644202017-02-27 18:29:45 +00007993
7994 if (done.IsLinked()) {
7995 __ Bind(&done);
7996 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007997
Roland Levillain3b359c72015-11-17 19:35:12 +00007998 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007999}
8000
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00008001void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
8002 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01008003 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00008004 InvokeRuntimeCallingConvention calling_convention;
8005 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8006}
8007
8008void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01008009 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
8010 instruction,
8011 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00008012 if (instruction->IsEnter()) {
8013 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
8014 } else {
8015 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
8016 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00008017}
8018
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008019void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
8020void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
8021void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008022
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008023void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008024 LocationSummary* locations =
8025 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
8026 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
8027 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008028 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008029 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008030 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00008031 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008032}
8033
8034void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
8035 HandleBitwiseOperation(instruction);
8036}
8037
8038void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
8039 HandleBitwiseOperation(instruction);
8040}
8041
8042void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
8043 HandleBitwiseOperation(instruction);
8044}
8045
Artem Serov7fc63502016-02-09 17:15:29 +00008046
8047void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
8048 LocationSummary* locations =
8049 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
8050 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
8051 || instruction->GetResultType() == Primitive::kPrimLong);
8052
8053 locations->SetInAt(0, Location::RequiresRegister());
8054 locations->SetInAt(1, Location::RequiresRegister());
8055 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8056}
8057
8058void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
8059 LocationSummary* locations = instruction->GetLocations();
8060 Location first = locations->InAt(0);
8061 Location second = locations->InAt(1);
8062 Location out = locations->Out();
8063
8064 if (instruction->GetResultType() == Primitive::kPrimInt) {
8065 Register first_reg = first.AsRegister<Register>();
8066 ShifterOperand second_reg(second.AsRegister<Register>());
8067 Register out_reg = out.AsRegister<Register>();
8068
8069 switch (instruction->GetOpKind()) {
8070 case HInstruction::kAnd:
8071 __ bic(out_reg, first_reg, second_reg);
8072 break;
8073 case HInstruction::kOr:
8074 __ orn(out_reg, first_reg, second_reg);
8075 break;
8076 // There is no EON on arm.
8077 case HInstruction::kXor:
8078 default:
8079 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
8080 UNREACHABLE();
8081 }
8082 return;
8083
8084 } else {
8085 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
8086 Register first_low = first.AsRegisterPairLow<Register>();
8087 Register first_high = first.AsRegisterPairHigh<Register>();
8088 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
8089 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
8090 Register out_low = out.AsRegisterPairLow<Register>();
8091 Register out_high = out.AsRegisterPairHigh<Register>();
8092
8093 switch (instruction->GetOpKind()) {
8094 case HInstruction::kAnd:
8095 __ bic(out_low, first_low, second_low);
8096 __ bic(out_high, first_high, second_high);
8097 break;
8098 case HInstruction::kOr:
8099 __ orn(out_low, first_low, second_low);
8100 __ orn(out_high, first_high, second_high);
8101 break;
8102 // There is no EON on arm.
8103 case HInstruction::kXor:
8104 default:
8105 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
8106 UNREACHABLE();
8107 }
8108 }
8109}
8110
Anton Kirilov74234da2017-01-13 14:42:47 +00008111void LocationsBuilderARM::VisitDataProcWithShifterOp(
8112 HDataProcWithShifterOp* instruction) {
8113 DCHECK(instruction->GetType() == Primitive::kPrimInt ||
8114 instruction->GetType() == Primitive::kPrimLong);
8115 LocationSummary* locations =
8116 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
8117 const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
8118 HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
8119
8120 locations->SetInAt(0, Location::RequiresRegister());
8121 locations->SetInAt(1, Location::RequiresRegister());
8122 locations->SetOut(Location::RequiresRegister(),
8123 overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
8124}
8125
8126void InstructionCodeGeneratorARM::VisitDataProcWithShifterOp(
8127 HDataProcWithShifterOp* instruction) {
8128 const LocationSummary* const locations = instruction->GetLocations();
8129 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
8130 const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
8131 const Location left = locations->InAt(0);
8132 const Location right = locations->InAt(1);
8133 const Location out = locations->Out();
8134
8135 if (instruction->GetType() == Primitive::kPrimInt) {
8136 DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
8137
8138 const Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
8139 ? right.AsRegisterPairLow<Register>()
8140 : right.AsRegister<Register>();
8141
8142 GenerateDataProcInstruction(kind,
8143 out.AsRegister<Register>(),
8144 left.AsRegister<Register>(),
8145 ShifterOperand(second,
8146 ShiftFromOpKind(op_kind),
8147 instruction->GetShiftAmount()),
8148 codegen_);
8149 } else {
8150 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
8151
8152 if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
8153 const Register second = right.AsRegister<Register>();
8154
8155 DCHECK_NE(out.AsRegisterPairLow<Register>(), second);
8156 GenerateDataProc(kind,
8157 out,
8158 left,
8159 ShifterOperand(second),
8160 ShifterOperand(second, ASR, 31),
8161 codegen_);
8162 } else {
8163 GenerateLongDataProc(instruction, codegen_);
8164 }
8165 }
8166}
8167
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008168void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
8169 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
8170 if (value == 0xffffffffu) {
8171 if (out != first) {
8172 __ mov(out, ShifterOperand(first));
8173 }
8174 return;
8175 }
8176 if (value == 0u) {
8177 __ mov(out, ShifterOperand(0));
8178 return;
8179 }
8180 ShifterOperand so;
8181 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
8182 __ and_(out, first, so);
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00008183 } else if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008184 __ bic(out, first, ShifterOperand(~value));
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00008185 } else {
8186 DCHECK(IsPowerOfTwo(value + 1));
8187 __ ubfx(out, first, 0, WhichPowerOf2(value + 1));
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008188 }
8189}
8190
8191void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
8192 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
8193 if (value == 0u) {
8194 if (out != first) {
8195 __ mov(out, ShifterOperand(first));
8196 }
8197 return;
8198 }
8199 if (value == 0xffffffffu) {
8200 __ mvn(out, ShifterOperand(0));
8201 return;
8202 }
8203 ShifterOperand so;
8204 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
8205 __ orr(out, first, so);
8206 } else {
8207 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
8208 __ orn(out, first, ShifterOperand(~value));
8209 }
8210}
8211
8212void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
8213 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
8214 if (value == 0u) {
8215 if (out != first) {
8216 __ mov(out, ShifterOperand(first));
8217 }
8218 return;
8219 }
8220 __ eor(out, first, ShifterOperand(value));
8221}
8222
Vladimir Marko59751a72016-08-05 14:37:27 +01008223void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
8224 Location first,
8225 uint64_t value) {
8226 Register out_low = out.AsRegisterPairLow<Register>();
8227 Register out_high = out.AsRegisterPairHigh<Register>();
8228 Register first_low = first.AsRegisterPairLow<Register>();
8229 Register first_high = first.AsRegisterPairHigh<Register>();
8230 uint32_t value_low = Low32Bits(value);
8231 uint32_t value_high = High32Bits(value);
8232 if (value_low == 0u) {
8233 if (out_low != first_low) {
8234 __ mov(out_low, ShifterOperand(first_low));
8235 }
8236 __ AddConstant(out_high, first_high, value_high);
8237 return;
8238 }
8239 __ AddConstantSetFlags(out_low, first_low, value_low);
8240 ShifterOperand so;
8241 if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
8242 __ adc(out_high, first_high, so);
8243 } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
8244 __ sbc(out_high, first_high, so);
8245 } else {
8246 LOG(FATAL) << "Unexpected constant " << value_high;
8247 UNREACHABLE();
8248 }
8249}
8250
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008251void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
8252 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008253 Location first = locations->InAt(0);
8254 Location second = locations->InAt(1);
8255 Location out = locations->Out();
8256
8257 if (second.IsConstant()) {
8258 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
8259 uint32_t value_low = Low32Bits(value);
8260 if (instruction->GetResultType() == Primitive::kPrimInt) {
8261 Register first_reg = first.AsRegister<Register>();
8262 Register out_reg = out.AsRegister<Register>();
8263 if (instruction->IsAnd()) {
8264 GenerateAndConst(out_reg, first_reg, value_low);
8265 } else if (instruction->IsOr()) {
8266 GenerateOrrConst(out_reg, first_reg, value_low);
8267 } else {
8268 DCHECK(instruction->IsXor());
8269 GenerateEorConst(out_reg, first_reg, value_low);
8270 }
8271 } else {
8272 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
8273 uint32_t value_high = High32Bits(value);
8274 Register first_low = first.AsRegisterPairLow<Register>();
8275 Register first_high = first.AsRegisterPairHigh<Register>();
8276 Register out_low = out.AsRegisterPairLow<Register>();
8277 Register out_high = out.AsRegisterPairHigh<Register>();
8278 if (instruction->IsAnd()) {
8279 GenerateAndConst(out_low, first_low, value_low);
8280 GenerateAndConst(out_high, first_high, value_high);
8281 } else if (instruction->IsOr()) {
8282 GenerateOrrConst(out_low, first_low, value_low);
8283 GenerateOrrConst(out_high, first_high, value_high);
8284 } else {
8285 DCHECK(instruction->IsXor());
8286 GenerateEorConst(out_low, first_low, value_low);
8287 GenerateEorConst(out_high, first_high, value_high);
8288 }
8289 }
8290 return;
8291 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008292
8293 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008294 Register first_reg = first.AsRegister<Register>();
8295 ShifterOperand second_reg(second.AsRegister<Register>());
8296 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008297 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008298 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008299 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008300 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008301 } else {
8302 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008303 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008304 }
8305 } else {
8306 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008307 Register first_low = first.AsRegisterPairLow<Register>();
8308 Register first_high = first.AsRegisterPairHigh<Register>();
8309 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
8310 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
8311 Register out_low = out.AsRegisterPairLow<Register>();
8312 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008313 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008314 __ and_(out_low, first_low, second_low);
8315 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008316 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008317 __ orr(out_low, first_low, second_low);
8318 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008319 } else {
8320 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008321 __ eor(out_low, first_low, second_low);
8322 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008323 }
8324 }
8325}
8326
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008327void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
8328 HInstruction* instruction,
8329 Location out,
8330 uint32_t offset,
8331 Location maybe_temp,
8332 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00008333 Register out_reg = out.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008334 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08008335 CHECK(kEmitCompilerReadBarrier);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008336 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00008337 if (kUseBakerReadBarrier) {
8338 // Load with fast path based Baker's read barrier.
8339 // /* HeapReference<Object> */ out = *(out + offset)
8340 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008341 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00008342 } else {
8343 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008344 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00008345 // in the following move operation, as we will need it for the
8346 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008347 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00008348 // /* HeapReference<Object> */ out = *(out + offset)
8349 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008350 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00008351 }
8352 } else {
8353 // Plain load with no read barrier.
8354 // /* HeapReference<Object> */ out = *(out + offset)
8355 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
8356 __ MaybeUnpoisonHeapReference(out_reg);
8357 }
8358}
8359
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008360void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
8361 HInstruction* instruction,
8362 Location out,
8363 Location obj,
8364 uint32_t offset,
8365 Location maybe_temp,
8366 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00008367 Register out_reg = out.AsRegister<Register>();
8368 Register obj_reg = obj.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008369 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08008370 CHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00008371 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008372 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00008373 // Load with fast path based Baker's read barrier.
8374 // /* HeapReference<Object> */ out = *(obj + offset)
8375 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008376 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00008377 } else {
8378 // Load with slow path based read barrier.
8379 // /* HeapReference<Object> */ out = *(obj + offset)
8380 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
8381 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
8382 }
8383 } else {
8384 // Plain load with no read barrier.
8385 // /* HeapReference<Object> */ out = *(obj + offset)
8386 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
8387 __ MaybeUnpoisonHeapReference(out_reg);
8388 }
8389}
8390
8391void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
8392 Location root,
8393 Register obj,
Mathieu Chartier31b12e32016-09-02 17:11:57 -07008394 uint32_t offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008395 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00008396 Register root_reg = root.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008397 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07008398 DCHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00008399 if (kUseBakerReadBarrier) {
8400 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
Roland Levillainba650a42017-03-06 13:52:32 +00008401 // Baker's read barrier are used.
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008402 if (kBakerReadBarrierLinkTimeThunksEnableForGcRoots &&
8403 !Runtime::Current()->UseJitCompilation()) {
8404 // Note that we do not actually check the value of `GetIsGcMarking()`
8405 // to decide whether to mark the loaded GC root or not. Instead, we
8406 // load into `temp` (actually kBakerCcEntrypointRegister) the read
8407 // barrier mark introspection entrypoint. If `temp` is null, it means
8408 // that `GetIsGcMarking()` is false, and vice versa.
8409 //
8410 // We use link-time generated thunks for the slow path. That thunk
8411 // checks the reference and jumps to the entrypoint if needed.
8412 //
8413 // temp = Thread::Current()->pReadBarrierMarkIntrospection
8414 // lr = &return_address;
8415 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
8416 // if (temp != nullptr) {
8417 // goto gc_root_thunk<root_reg>(lr)
8418 // }
8419 // return_address:
Roland Levillainc9285912015-12-18 10:38:42 +00008420
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008421 CheckLastTempIsBakerCcEntrypointRegister(instruction);
Vladimir Marko88abba22017-05-03 17:09:25 +01008422 bool narrow = CanEmitNarrowLdr(root_reg, obj, offset);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008423 uint32_t custom_data =
Vladimir Marko88abba22017-05-03 17:09:25 +01008424 linker::Thumb2RelativePatcher::EncodeBakerReadBarrierGcRootData(root_reg, narrow);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008425 Label* bne_label = codegen_->NewBakerReadBarrierPatch(custom_data);
Roland Levillainba650a42017-03-06 13:52:32 +00008426
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008427 // entrypoint_reg =
8428 // Thread::Current()->pReadBarrierMarkReg12, i.e. pReadBarrierMarkIntrospection.
8429 DCHECK_EQ(IP, 12);
8430 const int32_t entry_point_offset =
8431 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(IP);
8432 __ LoadFromOffset(kLoadWord, kBakerCcEntrypointRegister, TR, entry_point_offset);
Roland Levillainba650a42017-03-06 13:52:32 +00008433
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008434 Label return_address;
8435 __ AdrCode(LR, &return_address);
8436 __ CmpConstant(kBakerCcEntrypointRegister, 0);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008437 // Currently the offset is always within range. If that changes,
8438 // we shall have to split the load the same way as for fields.
8439 DCHECK_LT(offset, kReferenceLoadMinFarOffset);
Vladimir Marko88abba22017-05-03 17:09:25 +01008440 DCHECK(!down_cast<Thumb2Assembler*>(GetAssembler())->IsForced32Bit());
8441 ScopedForce32Bit maybe_force_32bit(down_cast<Thumb2Assembler*>(GetAssembler()), !narrow);
8442 int old_position = GetAssembler()->GetBuffer()->GetPosition();
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008443 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8444 EmitPlaceholderBne(codegen_, bne_label);
8445 __ Bind(&return_address);
Vladimir Marko88abba22017-05-03 17:09:25 +01008446 DCHECK_EQ(old_position - GetAssembler()->GetBuffer()->GetPosition(),
8447 narrow ? BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_NARROW_OFFSET
8448 : BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_WIDE_OFFSET);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008449 } else {
8450 // Note that we do not actually check the value of
8451 // `GetIsGcMarking()` to decide whether to mark the loaded GC
8452 // root or not. Instead, we load into `temp` the read barrier
8453 // mark entry point corresponding to register `root`. If `temp`
8454 // is null, it means that `GetIsGcMarking()` is false, and vice
8455 // versa.
8456 //
8457 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8458 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
8459 // if (temp != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8460 // // Slow path.
8461 // root = temp(root); // root = ReadBarrier::Mark(root); // Runtime entry point call.
8462 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008463
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008464 // Slow path marking the GC root `root`. The entrypoint will already be loaded in `temp`.
8465 Location temp = Location::RegisterLocation(LR);
8466 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
8467 instruction, root, /* entrypoint */ temp);
8468 codegen_->AddSlowPath(slow_path);
8469
8470 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8471 const int32_t entry_point_offset =
8472 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
8473 // Loading the entrypoint does not require a load acquire since it is only changed when
8474 // threads are suspended or running a checkpoint.
8475 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
8476
8477 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
8478 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8479 static_assert(
8480 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
8481 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
8482 "have different sizes.");
8483 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
8484 "art::mirror::CompressedReference<mirror::Object> and int32_t "
8485 "have different sizes.");
8486
8487 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8488 // checking GetIsGcMarking.
8489 __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
8490 __ Bind(slow_path->GetExitLabel());
8491 }
Roland Levillainc9285912015-12-18 10:38:42 +00008492 } else {
8493 // GC root loaded through a slow path for read barriers other
8494 // than Baker's.
8495 // /* GcRoot<mirror::Object>* */ root = obj + offset
8496 __ AddConstant(root_reg, obj, offset);
8497 // /* mirror::Object* */ root = root->Read()
8498 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
8499 }
8500 } else {
8501 // Plain GC root load with no read barrier.
8502 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
8503 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8504 // Note that GC roots are not affected by heap poisoning, thus we
8505 // do not have to unpoison `root_reg` here.
8506 }
8507}
8508
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008509void CodeGeneratorARM::MaybeAddBakerCcEntrypointTempForFields(LocationSummary* locations) {
8510 DCHECK(kEmitCompilerReadBarrier);
8511 DCHECK(kUseBakerReadBarrier);
8512 if (kBakerReadBarrierLinkTimeThunksEnableForFields) {
8513 if (!Runtime::Current()->UseJitCompilation()) {
8514 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
8515 }
8516 }
8517}
8518
Roland Levillainc9285912015-12-18 10:38:42 +00008519void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
8520 Location ref,
8521 Register obj,
8522 uint32_t offset,
8523 Location temp,
8524 bool needs_null_check) {
8525 DCHECK(kEmitCompilerReadBarrier);
8526 DCHECK(kUseBakerReadBarrier);
8527
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008528 if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
8529 !Runtime::Current()->UseJitCompilation()) {
8530 // Note that we do not actually check the value of `GetIsGcMarking()`
8531 // to decide whether to mark the loaded reference or not. Instead, we
8532 // load into `temp` (actually kBakerCcEntrypointRegister) the read
8533 // barrier mark introspection entrypoint. If `temp` is null, it means
8534 // that `GetIsGcMarking()` is false, and vice versa.
8535 //
8536 // We use link-time generated thunks for the slow path. That thunk checks
8537 // the holder and jumps to the entrypoint if needed. If the holder is not
8538 // gray, it creates a fake dependency and returns to the LDR instruction.
8539 //
8540 // temp = Thread::Current()->pReadBarrierMarkIntrospection
8541 // lr = &gray_return_address;
8542 // if (temp != nullptr) {
8543 // goto field_thunk<holder_reg, base_reg>(lr)
8544 // }
8545 // not_gray_return_address:
8546 // // Original reference load. If the offset is too large to fit
8547 // // into LDR, we use an adjusted base register here.
Vladimir Marko88abba22017-05-03 17:09:25 +01008548 // HeapReference<mirror::Object> reference = *(obj+offset);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008549 // gray_return_address:
8550
8551 DCHECK_ALIGNED(offset, sizeof(mirror::HeapReference<mirror::Object>));
Vladimir Marko88abba22017-05-03 17:09:25 +01008552 Register ref_reg = ref.AsRegister<Register>();
8553 bool narrow = CanEmitNarrowLdr(ref_reg, obj, offset);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008554 Register base = obj;
8555 if (offset >= kReferenceLoadMinFarOffset) {
8556 base = temp.AsRegister<Register>();
8557 DCHECK_NE(base, kBakerCcEntrypointRegister);
8558 static_assert(IsPowerOfTwo(kReferenceLoadMinFarOffset), "Expecting a power of 2.");
8559 __ AddConstant(base, obj, offset & ~(kReferenceLoadMinFarOffset - 1u));
8560 offset &= (kReferenceLoadMinFarOffset - 1u);
Vladimir Marko88abba22017-05-03 17:09:25 +01008561 // Use narrow LDR only for small offsets. Generating narrow encoding LDR for the large
8562 // offsets with `(offset & (kReferenceLoadMinFarOffset - 1u)) < 32u` would most likely
8563 // increase the overall code size when taking the generated thunks into account.
8564 DCHECK(!narrow);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008565 }
8566 CheckLastTempIsBakerCcEntrypointRegister(instruction);
8567 uint32_t custom_data =
Vladimir Marko88abba22017-05-03 17:09:25 +01008568 linker::Thumb2RelativePatcher::EncodeBakerReadBarrierFieldData(base, obj, narrow);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008569 Label* bne_label = NewBakerReadBarrierPatch(custom_data);
8570
8571 // entrypoint_reg =
8572 // Thread::Current()->pReadBarrierMarkReg12, i.e. pReadBarrierMarkIntrospection.
8573 DCHECK_EQ(IP, 12);
8574 const int32_t entry_point_offset =
8575 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(IP);
8576 __ LoadFromOffset(kLoadWord, kBakerCcEntrypointRegister, TR, entry_point_offset);
8577
8578 Label return_address;
8579 __ AdrCode(LR, &return_address);
8580 __ CmpConstant(kBakerCcEntrypointRegister, 0);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008581 EmitPlaceholderBne(this, bne_label);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008582 DCHECK_LT(offset, kReferenceLoadMinFarOffset);
Vladimir Marko88abba22017-05-03 17:09:25 +01008583 DCHECK(!down_cast<Thumb2Assembler*>(GetAssembler())->IsForced32Bit());
8584 ScopedForce32Bit maybe_force_32bit(down_cast<Thumb2Assembler*>(GetAssembler()), !narrow);
8585 int old_position = GetAssembler()->GetBuffer()->GetPosition();
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008586 __ LoadFromOffset(kLoadWord, ref_reg, base, offset);
8587 if (needs_null_check) {
8588 MaybeRecordImplicitNullCheck(instruction);
8589 }
8590 GetAssembler()->MaybeUnpoisonHeapReference(ref_reg);
8591 __ Bind(&return_address);
Vladimir Marko88abba22017-05-03 17:09:25 +01008592 DCHECK_EQ(old_position - GetAssembler()->GetBuffer()->GetPosition(),
8593 narrow ? BAKER_MARK_INTROSPECTION_FIELD_LDR_NARROW_OFFSET
8594 : BAKER_MARK_INTROSPECTION_FIELD_LDR_WIDE_OFFSET);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008595 return;
8596 }
8597
Roland Levillainc9285912015-12-18 10:38:42 +00008598 // /* HeapReference<Object> */ ref = *(obj + offset)
8599 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01008600 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00008601 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008602 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008603}
8604
8605void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
8606 Location ref,
8607 Register obj,
8608 uint32_t data_offset,
8609 Location index,
8610 Location temp,
8611 bool needs_null_check) {
8612 DCHECK(kEmitCompilerReadBarrier);
8613 DCHECK(kUseBakerReadBarrier);
8614
Roland Levillainbfea3352016-06-23 13:48:47 +01008615 static_assert(
8616 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
8617 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008618 ScaleFactor scale_factor = TIMES_4;
8619
8620 if (kBakerReadBarrierLinkTimeThunksEnableForArrays &&
8621 !Runtime::Current()->UseJitCompilation()) {
8622 // Note that we do not actually check the value of `GetIsGcMarking()`
8623 // to decide whether to mark the loaded reference or not. Instead, we
8624 // load into `temp` (actually kBakerCcEntrypointRegister) the read
8625 // barrier mark introspection entrypoint. If `temp` is null, it means
8626 // that `GetIsGcMarking()` is false, and vice versa.
8627 //
8628 // We use link-time generated thunks for the slow path. That thunk checks
8629 // the holder and jumps to the entrypoint if needed. If the holder is not
8630 // gray, it creates a fake dependency and returns to the LDR instruction.
8631 //
8632 // temp = Thread::Current()->pReadBarrierMarkIntrospection
8633 // lr = &gray_return_address;
8634 // if (temp != nullptr) {
8635 // goto field_thunk<holder_reg, base_reg>(lr)
8636 // }
8637 // not_gray_return_address:
8638 // // Original reference load. If the offset is too large to fit
8639 // // into LDR, we use an adjusted base register here.
Vladimir Marko88abba22017-05-03 17:09:25 +01008640 // HeapReference<mirror::Object> reference = data[index];
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008641 // gray_return_address:
8642
8643 DCHECK(index.IsValid());
8644 Register index_reg = index.AsRegister<Register>();
8645 Register ref_reg = ref.AsRegister<Register>();
8646 Register data_reg = temp.AsRegister<Register>();
8647 DCHECK_NE(data_reg, kBakerCcEntrypointRegister);
8648
8649 CheckLastTempIsBakerCcEntrypointRegister(instruction);
8650 uint32_t custom_data =
8651 linker::Thumb2RelativePatcher::EncodeBakerReadBarrierArrayData(data_reg);
8652 Label* bne_label = NewBakerReadBarrierPatch(custom_data);
8653
8654 // entrypoint_reg =
8655 // Thread::Current()->pReadBarrierMarkReg16, i.e. pReadBarrierMarkIntrospection.
8656 DCHECK_EQ(IP, 12);
8657 const int32_t entry_point_offset =
8658 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(IP);
8659 __ LoadFromOffset(kLoadWord, kBakerCcEntrypointRegister, TR, entry_point_offset);
8660 __ AddConstant(data_reg, obj, data_offset);
8661
8662 Label return_address;
8663 __ AdrCode(LR, &return_address);
8664 __ CmpConstant(kBakerCcEntrypointRegister, 0);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008665 EmitPlaceholderBne(this, bne_label);
Vladimir Marko88abba22017-05-03 17:09:25 +01008666 ScopedForce32Bit maybe_force_32bit(down_cast<Thumb2Assembler*>(GetAssembler()));
8667 int old_position = GetAssembler()->GetBuffer()->GetPosition();
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008668 __ ldr(ref_reg, Address(data_reg, index_reg, LSL, scale_factor));
8669 DCHECK(!needs_null_check); // The thunk cannot handle the null check.
8670 GetAssembler()->MaybeUnpoisonHeapReference(ref_reg);
8671 __ Bind(&return_address);
Vladimir Marko88abba22017-05-03 17:09:25 +01008672 DCHECK_EQ(old_position - GetAssembler()->GetBuffer()->GetPosition(),
8673 BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008674 return;
8675 }
8676
Roland Levillainc9285912015-12-18 10:38:42 +00008677 // /* HeapReference<Object> */ ref =
8678 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
8679 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008680 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008681}
8682
8683void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
8684 Location ref,
8685 Register obj,
8686 uint32_t offset,
8687 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01008688 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00008689 Location temp,
Roland Levillainff487002017-03-07 16:50:01 +00008690 bool needs_null_check) {
Roland Levillainc9285912015-12-18 10:38:42 +00008691 DCHECK(kEmitCompilerReadBarrier);
8692 DCHECK(kUseBakerReadBarrier);
8693
Roland Levillain54f869e2017-03-06 13:54:11 +00008694 // Query `art::Thread::Current()->GetIsGcMarking()` to decide
8695 // whether we need to enter the slow path to mark the reference.
8696 // Then, in the slow path, check the gray bit in the lock word of
8697 // the reference's holder (`obj`) to decide whether to mark `ref` or
8698 // not.
Roland Levillainc9285912015-12-18 10:38:42 +00008699 //
Roland Levillainba650a42017-03-06 13:52:32 +00008700 // Note that we do not actually check the value of `GetIsGcMarking()`;
Roland Levillainff487002017-03-07 16:50:01 +00008701 // instead, we load into `temp2` the read barrier mark entry point
8702 // corresponding to register `ref`. If `temp2` is null, it means
8703 // that `GetIsGcMarking()` is false, and vice versa.
8704 //
8705 // temp2 = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8706 // if (temp2 != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8707 // // Slow path.
8708 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8709 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
8710 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8711 // bool is_gray = (rb_state == ReadBarrier::GrayState());
8712 // if (is_gray) {
8713 // ref = temp2(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
8714 // }
8715 // } else {
8716 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8717 // }
8718
8719 Register temp_reg = temp.AsRegister<Register>();
8720
8721 // Slow path marking the object `ref` when the GC is marking. The
8722 // entrypoint will already be loaded in `temp2`.
8723 Location temp2 = Location::RegisterLocation(LR);
8724 SlowPathCodeARM* slow_path =
8725 new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierSlowPathARM(
8726 instruction,
8727 ref,
8728 obj,
8729 offset,
8730 index,
8731 scale_factor,
8732 needs_null_check,
8733 temp_reg,
8734 /* entrypoint */ temp2);
8735 AddSlowPath(slow_path);
8736
8737 // temp2 = Thread::Current()->pReadBarrierMarkReg ## ref.reg()
8738 const int32_t entry_point_offset =
8739 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref.reg());
8740 // Loading the entrypoint does not require a load acquire since it is only changed when
8741 // threads are suspended or running a checkpoint.
8742 __ LoadFromOffset(kLoadWord, temp2.AsRegister<Register>(), TR, entry_point_offset);
8743 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8744 // checking GetIsGcMarking.
8745 __ CompareAndBranchIfNonZero(temp2.AsRegister<Register>(), slow_path->GetEntryLabel());
8746 // Fast path: the GC is not marking: just load the reference.
8747 GenerateRawReferenceLoad(instruction, ref, obj, offset, index, scale_factor, needs_null_check);
8748 __ Bind(slow_path->GetExitLabel());
8749}
8750
8751void CodeGeneratorARM::UpdateReferenceFieldWithBakerReadBarrier(HInstruction* instruction,
8752 Location ref,
8753 Register obj,
8754 Location field_offset,
8755 Location temp,
8756 bool needs_null_check,
8757 Register temp2) {
8758 DCHECK(kEmitCompilerReadBarrier);
8759 DCHECK(kUseBakerReadBarrier);
8760
8761 // Query `art::Thread::Current()->GetIsGcMarking()` to decide
8762 // whether we need to enter the slow path to update the reference
8763 // field within `obj`. Then, in the slow path, check the gray bit
8764 // in the lock word of the reference's holder (`obj`) to decide
8765 // whether to mark `ref` and update the field or not.
8766 //
8767 // Note that we do not actually check the value of `GetIsGcMarking()`;
Roland Levillainba650a42017-03-06 13:52:32 +00008768 // instead, we load into `temp3` the read barrier mark entry point
8769 // corresponding to register `ref`. If `temp3` is null, it means
8770 // that `GetIsGcMarking()` is false, and vice versa.
8771 //
8772 // temp3 = Thread::Current()->pReadBarrierMarkReg ## root.reg()
Roland Levillainba650a42017-03-06 13:52:32 +00008773 // if (temp3 != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8774 // // Slow path.
Roland Levillain54f869e2017-03-06 13:54:11 +00008775 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8776 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
8777 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8778 // bool is_gray = (rb_state == ReadBarrier::GrayState());
8779 // if (is_gray) {
Roland Levillainff487002017-03-07 16:50:01 +00008780 // old_ref = ref;
Roland Levillain54f869e2017-03-06 13:54:11 +00008781 // ref = temp3(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
Roland Levillainff487002017-03-07 16:50:01 +00008782 // compareAndSwapObject(obj, field_offset, old_ref, ref);
Roland Levillain54f869e2017-03-06 13:54:11 +00008783 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008784 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008785
Roland Levillain35345a52017-02-27 14:32:08 +00008786 Register temp_reg = temp.AsRegister<Register>();
Roland Levillain1372c9f2017-01-13 11:47:39 +00008787
Roland Levillainff487002017-03-07 16:50:01 +00008788 // Slow path updating the object reference at address `obj +
8789 // field_offset` when the GC is marking. The entrypoint will already
8790 // be loaded in `temp3`.
Roland Levillainba650a42017-03-06 13:52:32 +00008791 Location temp3 = Location::RegisterLocation(LR);
Roland Levillainff487002017-03-07 16:50:01 +00008792 SlowPathCodeARM* slow_path =
8793 new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(
8794 instruction,
8795 ref,
8796 obj,
8797 /* offset */ 0u,
8798 /* index */ field_offset,
8799 /* scale_factor */ ScaleFactor::TIMES_1,
8800 needs_null_check,
8801 temp_reg,
8802 temp2,
8803 /* entrypoint */ temp3);
Roland Levillainba650a42017-03-06 13:52:32 +00008804 AddSlowPath(slow_path);
Roland Levillain35345a52017-02-27 14:32:08 +00008805
Roland Levillainba650a42017-03-06 13:52:32 +00008806 // temp3 = Thread::Current()->pReadBarrierMarkReg ## ref.reg()
8807 const int32_t entry_point_offset =
8808 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref.reg());
8809 // Loading the entrypoint does not require a load acquire since it is only changed when
8810 // threads are suspended or running a checkpoint.
8811 __ LoadFromOffset(kLoadWord, temp3.AsRegister<Register>(), TR, entry_point_offset);
Roland Levillainba650a42017-03-06 13:52:32 +00008812 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8813 // checking GetIsGcMarking.
8814 __ CompareAndBranchIfNonZero(temp3.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillainff487002017-03-07 16:50:01 +00008815 // Fast path: the GC is not marking: nothing to do (the field is
8816 // up-to-date, and we don't need to load the reference).
Roland Levillainba650a42017-03-06 13:52:32 +00008817 __ Bind(slow_path->GetExitLabel());
8818}
Roland Levillain35345a52017-02-27 14:32:08 +00008819
Roland Levillainba650a42017-03-06 13:52:32 +00008820void CodeGeneratorARM::GenerateRawReferenceLoad(HInstruction* instruction,
8821 Location ref,
8822 Register obj,
8823 uint32_t offset,
8824 Location index,
8825 ScaleFactor scale_factor,
8826 bool needs_null_check) {
8827 Register ref_reg = ref.AsRegister<Register>();
8828
Roland Levillainc9285912015-12-18 10:38:42 +00008829 if (index.IsValid()) {
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008830 // Load types involving an "index": ArrayGet,
8831 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8832 // intrinsics.
Roland Levillainba650a42017-03-06 13:52:32 +00008833 // /* HeapReference<mirror::Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00008834 if (index.IsConstant()) {
8835 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01008836 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00008837 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
8838 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01008839 // Handle the special case of the
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008840 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8841 // intrinsics, which use a register pair as index ("long
8842 // offset"), of which only the low part contains data.
Roland Levillainbfea3352016-06-23 13:48:47 +01008843 Register index_reg = index.IsRegisterPair()
8844 ? index.AsRegisterPairLow<Register>()
8845 : index.AsRegister<Register>();
8846 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00008847 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
8848 }
8849 } else {
Roland Levillainba650a42017-03-06 13:52:32 +00008850 // /* HeapReference<mirror::Object> */ ref = *(obj + offset)
Roland Levillainc9285912015-12-18 10:38:42 +00008851 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
8852 }
8853
Roland Levillainba650a42017-03-06 13:52:32 +00008854 if (needs_null_check) {
8855 MaybeRecordImplicitNullCheck(instruction);
8856 }
8857
Roland Levillainc9285912015-12-18 10:38:42 +00008858 // Object* ref = ref_addr->AsMirrorPtr()
8859 __ MaybeUnpoisonHeapReference(ref_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00008860}
8861
8862void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
8863 Location out,
8864 Location ref,
8865 Location obj,
8866 uint32_t offset,
8867 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008868 DCHECK(kEmitCompilerReadBarrier);
8869
Roland Levillainc9285912015-12-18 10:38:42 +00008870 // Insert a slow path based read barrier *after* the reference load.
8871 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008872 // If heap poisoning is enabled, the unpoisoning of the loaded
8873 // reference will be carried out by the runtime within the slow
8874 // path.
8875 //
8876 // Note that `ref` currently does not get unpoisoned (when heap
8877 // poisoning is enabled), which is alright as the `ref` argument is
8878 // not used by the artReadBarrierSlow entry point.
8879 //
8880 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008881 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
Roland Levillain3b359c72015-11-17 19:35:12 +00008882 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
8883 AddSlowPath(slow_path);
8884
Roland Levillain3b359c72015-11-17 19:35:12 +00008885 __ b(slow_path->GetEntryLabel());
8886 __ Bind(slow_path->GetExitLabel());
8887}
8888
Roland Levillainc9285912015-12-18 10:38:42 +00008889void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
8890 Location out,
8891 Location ref,
8892 Location obj,
8893 uint32_t offset,
8894 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008895 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00008896 // Baker's read barriers shall be handled by the fast path
8897 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
8898 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00008899 // If heap poisoning is enabled, unpoisoning will be taken care of
8900 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00008901 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00008902 } else if (kPoisonHeapReferences) {
8903 __ UnpoisonHeapReference(out.AsRegister<Register>());
8904 }
8905}
8906
Roland Levillainc9285912015-12-18 10:38:42 +00008907void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
8908 Location out,
8909 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008910 DCHECK(kEmitCompilerReadBarrier);
8911
Roland Levillainc9285912015-12-18 10:38:42 +00008912 // Insert a slow path based read barrier *after* the GC root load.
8913 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008914 // Note that GC roots are not affected by heap poisoning, so we do
8915 // not need to do anything special for this here.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008916 SlowPathCodeARM* slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00008917 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
8918 AddSlowPath(slow_path);
8919
Roland Levillain3b359c72015-11-17 19:35:12 +00008920 __ b(slow_path->GetEntryLabel());
8921 __ Bind(slow_path->GetExitLabel());
8922}
8923
Vladimir Markodc151b22015-10-15 18:02:30 +01008924HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
8925 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +00008926 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffraye807ff72017-01-23 09:03:12 +00008927 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01008928}
8929
Vladimir Markob4536b72015-11-24 13:45:23 +00008930Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
8931 Register temp) {
8932 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
8933 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
8934 if (!invoke->GetLocations()->Intrinsified()) {
8935 return location.AsRegister<Register>();
8936 }
8937 // For intrinsics we allow any location, so it may be on the stack.
8938 if (!location.IsRegister()) {
8939 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
8940 return temp;
8941 }
8942 // For register locations, check if the register was saved. If so, get it from the stack.
8943 // Note: There is a chance that the register was saved but not overwritten, so we could
8944 // save one load. However, since this is just an intrinsic slow path we prefer this
8945 // simple and more robust approach rather that trying to determine if that's the case.
8946 SlowPathCode* slow_path = GetCurrentSlowPath();
Vladimir Markod254f5c2017-06-02 15:18:36 +00008947 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
8948 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
Vladimir Markob4536b72015-11-24 13:45:23 +00008949 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
8950 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
8951 return temp;
8952 }
8953 return location.AsRegister<Register>();
8954}
8955
Vladimir Markoe7197bf2017-06-02 17:00:23 +01008956void CodeGeneratorARM::GenerateStaticOrDirectCall(
8957 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Vladimir Marko58155012015-08-19 12:49:41 +00008958 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
8959 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008960 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
8961 uint32_t offset =
8962 GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Vladimir Marko58155012015-08-19 12:49:41 +00008963 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008964 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
Vladimir Marko58155012015-08-19 12:49:41 +00008965 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008966 }
Vladimir Marko58155012015-08-19 12:49:41 +00008967 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00008968 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00008969 break;
Vladimir Marko65979462017-05-19 17:25:12 +01008970 case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
8971 DCHECK(GetCompilerOptions().IsBootImage());
8972 Register temp_reg = temp.AsRegister<Register>();
8973 PcRelativePatchInfo* labels = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
8974 __ BindTrackedLabel(&labels->movw_label);
8975 __ movw(temp_reg, /* placeholder */ 0u);
8976 __ BindTrackedLabel(&labels->movt_label);
8977 __ movt(temp_reg, /* placeholder */ 0u);
8978 __ BindTrackedLabel(&labels->add_pc_label);
8979 __ add(temp_reg, temp_reg, ShifterOperand(PC));
8980 break;
8981 }
Vladimir Marko58155012015-08-19 12:49:41 +00008982 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
8983 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
8984 break;
Vladimir Marko0eb882b2017-05-15 13:39:18 +01008985 case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
8986 Register temp_reg = temp.AsRegister<Register>();
8987 PcRelativePatchInfo* labels = NewMethodBssEntryPatch(
8988 MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
8989 __ BindTrackedLabel(&labels->movw_label);
8990 __ movw(temp_reg, /* placeholder */ 0u);
8991 __ BindTrackedLabel(&labels->movt_label);
8992 __ movt(temp_reg, /* placeholder */ 0u);
8993 __ BindTrackedLabel(&labels->add_pc_label);
8994 __ add(temp_reg, temp_reg, ShifterOperand(PC));
8995 __ LoadFromOffset(kLoadWord, temp_reg, temp_reg, /* offset */ 0);
Vladimir Markob4536b72015-11-24 13:45:23 +00008996 break;
8997 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01008998 case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
8999 GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
9000 return; // No code pointer retrieval; the runtime performs the call directly.
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01009001 }
Vladimir Marko58155012015-08-19 12:49:41 +00009002 }
9003
9004 switch (invoke->GetCodePtrLocation()) {
9005 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
9006 __ bl(GetFrameEntryLabel());
9007 break;
Vladimir Marko58155012015-08-19 12:49:41 +00009008 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
9009 // LR = callee_method->entry_point_from_quick_compiled_code_
9010 __ LoadFromOffset(
9011 kLoadWord, LR, callee_method.AsRegister<Register>(),
Andreas Gampe542451c2016-07-26 09:02:02 -07009012 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00009013 // LR()
9014 __ blx(LR);
9015 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08009016 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01009017 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08009018
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08009019 DCHECK(!IsLeafMethod());
9020}
9021
Vladimir Markoe7197bf2017-06-02 17:00:23 +01009022void CodeGeneratorARM::GenerateVirtualCall(
9023 HInvokeVirtual* invoke, Location temp_location, SlowPathCode* slow_path) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00009024 Register temp = temp_location.AsRegister<Register>();
9025 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
9026 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00009027
9028 // Use the calling convention instead of the location of the receiver, as
9029 // intrinsics may have put the receiver in a different register. In the intrinsics
9030 // slow path, the arguments have been moved to the right place, so here we are
9031 // guaranteed that the receiver is the first register of the calling convention.
9032 InvokeDexCallingConvention calling_convention;
9033 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00009034 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00009035 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00009036 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00009037 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00009038 // Instead of simply (possibly) unpoisoning `temp` here, we should
9039 // emit a read barrier for the previous class reference load.
9040 // However this is not required in practice, as this is an
9041 // intermediate/temporary reference and because the current
9042 // concurrent copying collector keeps the from-space memory
9043 // intact/accessible until the end of the marking phase (the
9044 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00009045 __ MaybeUnpoisonHeapReference(temp);
9046 // temp = temp->GetMethodAt(method_offset);
9047 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07009048 kArmPointerSize).Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00009049 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
9050 // LR = temp->GetEntryPoint();
9051 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
9052 // LR();
9053 __ blx(LR);
Vladimir Markoe7197bf2017-06-02 17:00:23 +01009054 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00009055}
9056
Vladimir Marko65979462017-05-19 17:25:12 +01009057CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeMethodPatch(
9058 MethodReference target_method) {
9059 return NewPcRelativePatch(*target_method.dex_file,
9060 target_method.dex_method_index,
9061 &pc_relative_method_patches_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00009062}
9063
Vladimir Marko0eb882b2017-05-15 13:39:18 +01009064CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewMethodBssEntryPatch(
9065 MethodReference target_method) {
9066 return NewPcRelativePatch(*target_method.dex_file,
9067 target_method.dex_method_index,
9068 &method_bss_entry_patches_);
9069}
9070
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01009071CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
Andreas Gampea5b09a62016-11-17 15:21:22 -08009072 const DexFile& dex_file, dex::TypeIndex type_index) {
9073 return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01009074}
9075
Vladimir Marko1998cd02017-01-13 13:02:58 +00009076CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
9077 const DexFile& dex_file, dex::TypeIndex type_index) {
9078 return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
9079}
9080
Vladimir Marko65979462017-05-19 17:25:12 +01009081CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
9082 const DexFile& dex_file, dex::StringIndex string_index) {
9083 return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
9084}
9085
Vladimir Markocac5a7e2016-02-22 10:39:50 +00009086CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
9087 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
9088 patches->emplace_back(dex_file, offset_or_index);
9089 return &patches->back();
9090}
9091
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01009092Label* CodeGeneratorARM::NewBakerReadBarrierPatch(uint32_t custom_data) {
9093 baker_read_barrier_patches_.emplace_back(custom_data);
9094 return &baker_read_barrier_patches_.back().label;
9095}
9096
Vladimir Markocac5a7e2016-02-22 10:39:50 +00009097Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
Richard Uhlerc52f3032017-03-02 13:45:45 +00009098 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00009099}
9100
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009101Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00009102 dex::StringIndex string_index,
9103 Handle<mirror::String> handle) {
9104 jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
9105 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009106 return jit_string_patches_.GetOrCreate(
9107 StringReference(&dex_file, string_index),
9108 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
9109}
9110
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009111Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
9112 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00009113 Handle<mirror::Class> handle) {
9114 jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
9115 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009116 return jit_class_patches_.GetOrCreate(
9117 TypeReference(&dex_file, type_index),
9118 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
9119}
9120
Vladimir Markoaad75c62016-10-03 08:46:48 +00009121template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
9122inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
9123 const ArenaDeque<PcRelativePatchInfo>& infos,
9124 ArenaVector<LinkerPatch>* linker_patches) {
9125 for (const PcRelativePatchInfo& info : infos) {
9126 const DexFile& dex_file = info.target_dex_file;
9127 size_t offset_or_index = info.offset_or_index;
9128 DCHECK(info.add_pc_label.IsBound());
9129 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
9130 // Add MOVW patch.
9131 DCHECK(info.movw_label.IsBound());
9132 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
9133 linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
9134 // Add MOVT patch.
9135 DCHECK(info.movt_label.IsBound());
9136 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
9137 linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
9138 }
9139}
9140
Vladimir Marko58155012015-08-19 12:49:41 +00009141void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
9142 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00009143 size_t size =
Vladimir Marko65979462017-05-19 17:25:12 +01009144 /* MOVW+MOVT for each entry */ 2u * pc_relative_method_patches_.size() +
Vladimir Marko0eb882b2017-05-15 13:39:18 +01009145 /* MOVW+MOVT for each entry */ 2u * method_bss_entry_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00009146 /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01009147 /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
Vladimir Marko65979462017-05-19 17:25:12 +01009148 /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01009149 baker_read_barrier_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00009150 linker_patches->reserve(size);
Vladimir Marko65979462017-05-19 17:25:12 +01009151 if (GetCompilerOptions().IsBootImage()) {
9152 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
Vladimir Markoaad75c62016-10-03 08:46:48 +00009153 linker_patches);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00009154 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
9155 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00009156 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
9157 linker_patches);
Vladimir Marko65979462017-05-19 17:25:12 +01009158 } else {
9159 DCHECK(pc_relative_method_patches_.empty());
9160 DCHECK(pc_relative_type_patches_.empty());
9161 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
9162 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00009163 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01009164 EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
9165 linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00009166 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
9167 linker_patches);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01009168 for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
9169 linker_patches->push_back(LinkerPatch::BakerReadBarrierBranchPatch(info.label.Position(),
9170 info.custom_data));
9171 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00009172 DCHECK_EQ(size, linker_patches->size());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00009173}
9174
9175Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
9176 return map->GetOrCreate(
9177 value,
9178 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00009179}
9180
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03009181void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
9182 LocationSummary* locations =
9183 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
9184 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
9185 Location::RequiresRegister());
9186 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
9187 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
9188 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
9189}
9190
9191void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
9192 LocationSummary* locations = instr->GetLocations();
9193 Register res = locations->Out().AsRegister<Register>();
9194 Register accumulator =
9195 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
9196 Register mul_left =
9197 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
9198 Register mul_right =
9199 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
9200
9201 if (instr->GetOpKind() == HInstruction::kAdd) {
9202 __ mla(res, mul_left, mul_right, accumulator);
9203 } else {
9204 __ mls(res, mul_left, mul_right, accumulator);
9205 }
9206}
9207
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01009208void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00009209 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00009210 LOG(FATAL) << "Unreachable";
9211}
9212
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01009213void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00009214 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00009215 LOG(FATAL) << "Unreachable";
9216}
9217
Mark Mendellfe57faa2015-09-18 09:26:15 -04009218// Simple implementation of packed switch - generate cascaded compare/jumps.
9219void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
9220 LocationSummary* locations =
9221 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
9222 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009223 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07009224 codegen_->GetAssembler()->IsThumb()) {
9225 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
9226 if (switch_instr->GetStartValue() != 0) {
9227 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
9228 }
9229 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04009230}
9231
9232void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
9233 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07009234 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04009235 LocationSummary* locations = switch_instr->GetLocations();
9236 Register value_reg = locations->InAt(0).AsRegister<Register>();
9237 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
9238
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009239 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07009240 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009241 Register temp_reg = IP;
9242 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
9243 // the immediate, because IP is used as the destination register. For the other
9244 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
9245 // and they can be encoded in the instruction without making use of IP register.
9246 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
9247
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07009248 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009249 // Jump to successors[0] if value == lower_bound.
9250 __ b(codegen_->GetLabelOf(successors[0]), EQ);
9251 int32_t last_index = 0;
9252 for (; num_entries - last_index > 2; last_index += 2) {
9253 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
9254 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
9255 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
9256 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
9257 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
9258 }
9259 if (num_entries - last_index == 2) {
9260 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00009261 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009262 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07009263 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04009264
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07009265 // And the default for any other value.
9266 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
9267 __ b(codegen_->GetLabelOf(default_block));
9268 }
9269 } else {
9270 // Create a table lookup.
9271 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
9272
9273 // Materialize a pointer to the switch table
9274 std::vector<Label*> labels(num_entries);
9275 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
9276 for (uint32_t i = 0; i < num_entries; i++) {
9277 labels[i] = codegen_->GetLabelOf(successors[i]);
9278 }
9279 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
9280
9281 // Remove the bias.
9282 Register key_reg;
9283 if (lower_bound != 0) {
9284 key_reg = locations->GetTemp(1).AsRegister<Register>();
9285 __ AddConstant(key_reg, value_reg, -lower_bound);
9286 } else {
9287 key_reg = value_reg;
9288 }
9289
9290 // Check whether the value is in the table, jump to default block if not.
9291 __ CmpConstant(key_reg, num_entries - 1);
9292 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
9293
9294 // Load the displacement from the table.
9295 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
9296
9297 // Dispatch is a direct add to the PC (for Thumb2).
9298 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04009299 }
9300}
9301
Andreas Gampe85b62f22015-09-09 13:15:38 -07009302void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
9303 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00009304 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07009305 return;
9306 }
9307
9308 DCHECK_NE(type, Primitive::kPrimVoid);
9309
9310 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
9311 if (return_loc.Equals(trg)) {
9312 return;
9313 }
9314
9315 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
9316 // with the last branch.
9317 if (type == Primitive::kPrimLong) {
9318 HParallelMove parallel_move(GetGraph()->GetArena());
9319 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
9320 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
9321 GetMoveResolver()->EmitNativeCode(&parallel_move);
9322 } else if (type == Primitive::kPrimDouble) {
9323 HParallelMove parallel_move(GetGraph()->GetArena());
9324 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
9325 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
9326 GetMoveResolver()->EmitNativeCode(&parallel_move);
9327 } else {
9328 // Let the parallel move resolver take care of all of this.
9329 HParallelMove parallel_move(GetGraph()->GetArena());
9330 parallel_move.AddMove(return_loc, trg, type, nullptr);
9331 GetMoveResolver()->EmitNativeCode(&parallel_move);
9332 }
9333}
9334
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009335void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
9336 LocationSummary* locations =
9337 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
9338 locations->SetInAt(0, Location::RequiresRegister());
9339 locations->SetOut(Location::RequiresRegister());
9340}
9341
9342void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
9343 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00009344 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009345 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009346 instruction->GetIndex(), kArmPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009347 __ LoadFromOffset(kLoadWord,
9348 locations->Out().AsRegister<Register>(),
9349 locations->InAt(0).AsRegister<Register>(),
9350 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009351 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009352 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00009353 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009354 __ LoadFromOffset(kLoadWord,
9355 locations->Out().AsRegister<Register>(),
9356 locations->InAt(0).AsRegister<Register>(),
9357 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
9358 __ LoadFromOffset(kLoadWord,
9359 locations->Out().AsRegister<Register>(),
9360 locations->Out().AsRegister<Register>(),
9361 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009362 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009363}
9364
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009365static void PatchJitRootUse(uint8_t* code,
9366 const uint8_t* roots_data,
9367 Literal* literal,
9368 uint64_t index_in_table) {
9369 DCHECK(literal->GetLabel()->IsBound());
9370 uint32_t literal_offset = literal->GetLabel()->Position();
9371 uintptr_t address =
9372 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
9373 uint8_t* data = code + literal_offset;
9374 reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
9375}
9376
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009377void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
9378 for (const auto& entry : jit_string_patches_) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +01009379 const StringReference& string_reference = entry.first;
9380 Literal* table_entry_literal = entry.second;
9381 const auto it = jit_string_roots_.find(string_reference);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009382 DCHECK(it != jit_string_roots_.end());
Vladimir Marko7d157fc2017-05-10 16:29:23 +01009383 uint64_t index_in_table = it->second;
9384 PatchJitRootUse(code, roots_data, table_entry_literal, index_in_table);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009385 }
9386 for (const auto& entry : jit_class_patches_) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +01009387 const TypeReference& type_reference = entry.first;
9388 Literal* table_entry_literal = entry.second;
9389 const auto it = jit_class_roots_.find(type_reference);
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009390 DCHECK(it != jit_class_roots_.end());
Vladimir Marko7d157fc2017-05-10 16:29:23 +01009391 uint64_t index_in_table = it->second;
9392 PatchJitRootUse(code, roots_data, table_entry_literal, index_in_table);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009393 }
9394}
9395
Roland Levillain4d027112015-07-01 15:41:14 +01009396#undef __
9397#undef QUICK_ENTRY_POINT
9398
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00009399} // namespace arm
9400} // namespace art