blob: 35dccd645d98489a9e0ae801fc538de49ccd52ee [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"
Zheng Xuc6667102015-05-15 16:08:45 +080022#include "code_generator_utils.h"
Anton Kirilov74234da2017-01-13 14:42:47 +000023#include "common_arm.h"
Vladimir Marko58155012015-08-19 12:49:41 +000024#include "compiled_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070025#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010026#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080027#include "intrinsics.h"
28#include "intrinsics_arm.h"
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010029#include "linker/arm/relative_patcher_thumb2.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070030#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070031#include "mirror/class-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070032#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010033#include "utils/arm/assembler_arm.h"
34#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000035#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010036#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000037
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000038namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010039
Roland Levillain3b359c72015-11-17 19:35:12 +000040template<class MirrorType>
41class GcRoot;
42
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000043namespace arm {
44
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000045static bool ExpectedPairLayout(Location location) {
46 // We expected this for both core and fpu register pairs.
47 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
48}
49
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010050static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010051static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010052
David Brazdil58282f42016-01-14 12:45:10 +000053static constexpr Register kCoreAlwaysSpillRegister = R5;
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000054static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070055 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000056static constexpr SRegister kFpuCalleeSaves[] =
57 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010058
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000059// D31 cannot be split into two S registers, and the register allocator only works on
60// S registers. Therefore there is no need to block it.
61static constexpr DRegister DTMP = D31;
62
Vladimir Markof3e0ee22015-12-17 15:23:13 +000063static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070064
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010065// Reference load (except object array loads) is using LDR Rt, [Rn, #offset] which can handle
66// offset < 4KiB. For offsets >= 4KiB, the load shall be emitted as two or more instructions.
67// For the Baker read barrier implementation using link-generated thunks we need to split
68// the offset explicitly.
69constexpr uint32_t kReferenceLoadMinFarOffset = 4 * KB;
70
71// Flags controlling the use of link-time generated thunks for Baker read barriers.
72constexpr bool kBakerReadBarrierLinkTimeThunksEnableForFields = true;
73constexpr bool kBakerReadBarrierLinkTimeThunksEnableForArrays = true;
74constexpr bool kBakerReadBarrierLinkTimeThunksEnableForGcRoots = true;
75
76// The reserved entrypoint register for link-time generated thunks.
77const Register kBakerCcEntrypointRegister = R4;
78
Roland Levillain7cbd27f2016-08-11 23:53:33 +010079// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
80#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070081#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010082
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010083static inline void CheckLastTempIsBakerCcEntrypointRegister(HInstruction* instruction) {
84 DCHECK_EQ(static_cast<uint32_t>(kBakerCcEntrypointRegister),
85 linker::Thumb2RelativePatcher::kBakerCcEntrypointRegister);
86 DCHECK_NE(instruction->GetLocations()->GetTempCount(), 0u);
87 DCHECK_EQ(kBakerCcEntrypointRegister,
88 instruction->GetLocations()->GetTemp(
89 instruction->GetLocations()->GetTempCount() - 1u).AsRegister<Register>());
90}
91
92static inline void EmitPlaceholderBne(CodeGeneratorARM* codegen, Label* bne_label) {
93 DCHECK(down_cast<Thumb2Assembler*>(codegen->GetAssembler())->IsForced32Bit());
94 __ BindTrackedLabel(bne_label);
95 Label placeholder_label;
96 __ b(&placeholder_label, NE); // Placeholder, patched at link-time.
97 __ Bind(&placeholder_label);
98}
99
Artem Serovf4d6aee2016-07-11 10:41:45 +0100100static constexpr int kRegListThreshold = 4;
101
Artem Serovd300d8f2016-07-15 14:00:56 +0100102// SaveLiveRegisters and RestoreLiveRegisters from SlowPathCodeARM operate on sets of S registers,
103// for each live D registers they treat two corresponding S registers as live ones.
104//
105// Two following functions (SaveContiguousSRegisterList, RestoreContiguousSRegisterList) build
106// from a list of contiguous S registers a list of contiguous D registers (processing first/last
107// S registers corner cases) and save/restore this new list treating them as D registers.
108// - decreasing code size
109// - avoiding hazards on Cortex-A57, when a pair of S registers for an actual live D register is
110// restored and then used in regular non SlowPath code as D register.
111//
112// For the following example (v means the S register is live):
113// D names: | D0 | D1 | D2 | D4 | ...
114// S names: | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | ...
115// Live? | | v | v | v | v | v | v | | ...
116//
117// S1 and S6 will be saved/restored independently; D registers list (D1, D2) will be processed
118// as D registers.
119static size_t SaveContiguousSRegisterList(size_t first,
120 size_t last,
121 CodeGenerator* codegen,
122 size_t stack_offset) {
123 DCHECK_LE(first, last);
124 if ((first == last) && (first == 0)) {
125 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first);
126 return stack_offset;
127 }
128 if (first % 2 == 1) {
129 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first++);
130 }
131
132 bool save_last = false;
133 if (last % 2 == 0) {
134 save_last = true;
135 --last;
136 }
137
138 if (first < last) {
139 DRegister d_reg = static_cast<DRegister>(first / 2);
140 DCHECK_EQ((last - first + 1) % 2, 0u);
141 size_t number_of_d_regs = (last - first + 1) / 2;
142
143 if (number_of_d_regs == 1) {
Scott Wakelinga7812ae2016-10-17 10:03:36 +0100144 __ StoreDToOffset(d_reg, SP, stack_offset);
Artem Serovd300d8f2016-07-15 14:00:56 +0100145 } else if (number_of_d_regs > 1) {
146 __ add(IP, SP, ShifterOperand(stack_offset));
147 __ vstmiad(IP, d_reg, number_of_d_regs);
148 }
149 stack_offset += number_of_d_regs * kArmWordSize * 2;
150 }
151
152 if (save_last) {
153 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, last + 1);
154 }
155
156 return stack_offset;
157}
158
159static size_t RestoreContiguousSRegisterList(size_t first,
160 size_t last,
161 CodeGenerator* codegen,
162 size_t stack_offset) {
163 DCHECK_LE(first, last);
164 if ((first == last) && (first == 0)) {
165 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first);
166 return stack_offset;
167 }
168 if (first % 2 == 1) {
169 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first++);
170 }
171
172 bool restore_last = false;
173 if (last % 2 == 0) {
174 restore_last = true;
175 --last;
176 }
177
178 if (first < last) {
179 DRegister d_reg = static_cast<DRegister>(first / 2);
180 DCHECK_EQ((last - first + 1) % 2, 0u);
181 size_t number_of_d_regs = (last - first + 1) / 2;
182 if (number_of_d_regs == 1) {
183 __ LoadDFromOffset(d_reg, SP, stack_offset);
184 } else if (number_of_d_regs > 1) {
185 __ add(IP, SP, ShifterOperand(stack_offset));
186 __ vldmiad(IP, d_reg, number_of_d_regs);
187 }
188 stack_offset += number_of_d_regs * kArmWordSize * 2;
189 }
190
191 if (restore_last) {
192 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, last + 1);
193 }
194
195 return stack_offset;
196}
197
Artem Serovf4d6aee2016-07-11 10:41:45 +0100198void SlowPathCodeARM::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
199 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
200 size_t orig_offset = stack_offset;
201
202 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
203 for (uint32_t i : LowToHighBits(core_spills)) {
204 // If the register holds an object, update the stack mask.
205 if (locations->RegisterContainsObject(i)) {
206 locations->SetStackBit(stack_offset / kVRegSize);
207 }
208 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
209 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
210 saved_core_stack_offsets_[i] = stack_offset;
211 stack_offset += kArmWordSize;
212 }
213
214 int reg_num = POPCOUNT(core_spills);
215 if (reg_num != 0) {
216 if (reg_num > kRegListThreshold) {
217 __ StoreList(RegList(core_spills), orig_offset);
218 } else {
219 stack_offset = orig_offset;
220 for (uint32_t i : LowToHighBits(core_spills)) {
221 stack_offset += codegen->SaveCoreRegister(stack_offset, i);
222 }
223 }
224 }
225
Artem Serovd300d8f2016-07-15 14:00:56 +0100226 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
227 orig_offset = stack_offset;
Vladimir Marko804b03f2016-09-14 16:26:36 +0100228 for (uint32_t i : LowToHighBits(fp_spills)) {
Artem Serovf4d6aee2016-07-11 10:41:45 +0100229 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
230 saved_fpu_stack_offsets_[i] = stack_offset;
Artem Serovd300d8f2016-07-15 14:00:56 +0100231 stack_offset += kArmWordSize;
Artem Serovf4d6aee2016-07-11 10:41:45 +0100232 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100233
234 stack_offset = orig_offset;
235 while (fp_spills != 0u) {
236 uint32_t begin = CTZ(fp_spills);
237 uint32_t tmp = fp_spills + (1u << begin);
238 fp_spills &= tmp; // Clear the contiguous range of 1s.
239 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
240 stack_offset = SaveContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
241 }
242 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100243}
244
245void SlowPathCodeARM::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
246 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
247 size_t orig_offset = stack_offset;
248
249 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
250 for (uint32_t i : LowToHighBits(core_spills)) {
251 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
252 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
253 stack_offset += kArmWordSize;
254 }
255
256 int reg_num = POPCOUNT(core_spills);
257 if (reg_num != 0) {
258 if (reg_num > kRegListThreshold) {
259 __ LoadList(RegList(core_spills), orig_offset);
260 } else {
261 stack_offset = orig_offset;
262 for (uint32_t i : LowToHighBits(core_spills)) {
263 stack_offset += codegen->RestoreCoreRegister(stack_offset, i);
264 }
265 }
266 }
267
Artem Serovd300d8f2016-07-15 14:00:56 +0100268 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
269 while (fp_spills != 0u) {
270 uint32_t begin = CTZ(fp_spills);
271 uint32_t tmp = fp_spills + (1u << begin);
272 fp_spills &= tmp; // Clear the contiguous range of 1s.
273 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
274 stack_offset = RestoreContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
Artem Serovf4d6aee2016-07-11 10:41:45 +0100275 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100276 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100277}
278
279class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100280 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100281 explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100282
Alexandre Rames67555f72014-11-18 10:55:16 +0000283 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100284 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100285 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000286 if (instruction_->CanThrowIntoCatchBlock()) {
287 // Live registers will be restored in the catch block if caught.
288 SaveLiveRegisters(codegen, instruction_->GetLocations());
289 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100290 arm_codegen->InvokeRuntime(kQuickThrowNullPointer,
291 instruction_,
292 instruction_->GetDexPc(),
293 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000294 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100295 }
296
Alexandre Rames8158f282015-08-07 10:26:17 +0100297 bool IsFatal() const OVERRIDE { return true; }
298
Alexandre Rames9931f312015-06-19 14:47:01 +0100299 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
300
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100301 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100302 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
303};
304
Artem Serovf4d6aee2016-07-11 10:41:45 +0100305class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
Calin Juravled0d48522014-11-04 16:40:20 +0000306 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100307 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCodeARM(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000308
Alexandre Rames67555f72014-11-18 10:55:16 +0000309 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000310 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
311 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100312 arm_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000313 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000314 }
315
Alexandre Rames8158f282015-08-07 10:26:17 +0100316 bool IsFatal() const OVERRIDE { return true; }
317
Alexandre Rames9931f312015-06-19 14:47:01 +0100318 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
319
Calin Juravled0d48522014-11-04 16:40:20 +0000320 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000321 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
322};
323
Artem Serovf4d6aee2016-07-11 10:41:45 +0100324class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000325 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000326 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100327 : SlowPathCodeARM(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000328
Alexandre Rames67555f72014-11-18 10:55:16 +0000329 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100330 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000331 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100332 arm_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000333 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100334 if (successor_ == nullptr) {
335 __ b(GetReturnLabel());
336 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100337 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100338 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000339 }
340
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100341 Label* GetReturnLabel() {
342 DCHECK(successor_ == nullptr);
343 return &return_label_;
344 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000345
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100346 HBasicBlock* GetSuccessor() const {
347 return successor_;
348 }
349
Alexandre Rames9931f312015-06-19 14:47:01 +0100350 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
351
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000352 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100353 // If not null, the block to branch to after the suspend check.
354 HBasicBlock* const successor_;
355
356 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000357 Label return_label_;
358
359 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
360};
361
Artem Serovf4d6aee2016-07-11 10:41:45 +0100362class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100363 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100364 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100365 : SlowPathCodeARM(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100366
Alexandre Rames67555f72014-11-18 10:55:16 +0000367 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100368 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100369 LocationSummary* locations = instruction_->GetLocations();
370
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100371 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000372 if (instruction_->CanThrowIntoCatchBlock()) {
373 // Live registers will be restored in the catch block if caught.
374 SaveLiveRegisters(codegen, instruction_->GetLocations());
375 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000376 // We're moving two locations to locations that could overlap, so we need a parallel
377 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100378 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000379 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100380 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000381 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100382 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100383 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100384 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
385 Primitive::kPrimInt);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100386 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
387 ? kQuickThrowStringBounds
388 : kQuickThrowArrayBounds;
389 arm_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100390 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000391 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100392 }
393
Alexandre Rames8158f282015-08-07 10:26:17 +0100394 bool IsFatal() const OVERRIDE { return true; }
395
Alexandre Rames9931f312015-06-19 14:47:01 +0100396 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
397
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100398 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100399 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
400};
401
Artem Serovf4d6aee2016-07-11 10:41:45 +0100402class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100403 public:
Vladimir Markoea4c1262017-02-06 19:59:33 +0000404 LoadClassSlowPathARM(HLoadClass* cls, HInstruction* at, uint32_t dex_pc, bool do_clinit)
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000405 : SlowPathCodeARM(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000406 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
407 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100408
Alexandre Rames67555f72014-11-18 10:55:16 +0000409 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000410 LocationSummary* locations = instruction_->GetLocations();
Vladimir Markoea4c1262017-02-06 19:59:33 +0000411 Location out = locations->Out();
412 constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000413
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100414 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
415 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000416 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100417
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100418 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoea4c1262017-02-06 19:59:33 +0000419 // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
420 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
421 bool is_load_class_bss_entry =
422 (cls_ == instruction_) && (cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry);
423 Register entry_address = kNoRegister;
424 if (is_load_class_bss_entry && call_saves_everything_except_r0) {
425 Register temp = locations->GetTemp(0).AsRegister<Register>();
426 // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
427 // the kSaveEverything call.
428 bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
429 entry_address = temp_is_r0 ? out.AsRegister<Register>() : temp;
430 DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
431 if (temp_is_r0) {
432 __ mov(entry_address, ShifterOperand(temp));
433 }
434 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000435 dex::TypeIndex type_index = cls_->GetTypeIndex();
436 __ LoadImmediate(calling_convention.GetRegisterAt(0), type_index.index_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100437 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
438 : kQuickInitializeType;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000439 arm_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000440 if (do_clinit_) {
441 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
442 } else {
443 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
444 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000445
Vladimir Markoea4c1262017-02-06 19:59:33 +0000446 // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
447 if (is_load_class_bss_entry) {
448 if (call_saves_everything_except_r0) {
449 // The class entry address was preserved in `entry_address` thanks to kSaveEverything.
450 __ str(R0, Address(entry_address));
451 } else {
452 // For non-Baker read barrier, we need to re-calculate the address of the string entry.
453 Register temp = IP;
454 CodeGeneratorARM::PcRelativePatchInfo* labels =
455 arm_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
456 __ BindTrackedLabel(&labels->movw_label);
457 __ movw(temp, /* placeholder */ 0u);
458 __ BindTrackedLabel(&labels->movt_label);
459 __ movt(temp, /* placeholder */ 0u);
460 __ BindTrackedLabel(&labels->add_pc_label);
461 __ add(temp, temp, ShifterOperand(PC));
462 __ str(R0, Address(temp));
463 }
464 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000465 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000466 if (out.IsValid()) {
467 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000468 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
469 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000470 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100471 __ b(GetExitLabel());
472 }
473
Alexandre Rames9931f312015-06-19 14:47:01 +0100474 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
475
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100476 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000477 // The class this slow path will load.
478 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100479
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000480 // The dex PC of `at_`.
481 const uint32_t dex_pc_;
482
483 // Whether to initialize the class.
484 const bool do_clinit_;
485
486 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100487};
488
Vladimir Markoaad75c62016-10-03 08:46:48 +0000489class LoadStringSlowPathARM : public SlowPathCodeARM {
490 public:
491 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCodeARM(instruction) {}
492
493 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Markoea4c1262017-02-06 19:59:33 +0000494 DCHECK(instruction_->IsLoadString());
495 DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000496 LocationSummary* locations = instruction_->GetLocations();
497 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100498 HLoadString* load = instruction_->AsLoadString();
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000499 const dex::StringIndex string_index = load->GetStringIndex();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100500 Register out = locations->Out().AsRegister<Register>();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100501 constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000502
503 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
504 __ Bind(GetEntryLabel());
505 SaveLiveRegisters(codegen, locations);
506
507 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100508 // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
Vladimir Markoea4c1262017-02-06 19:59:33 +0000509 // the kSaveEverything call.
510 Register entry_address = kNoRegister;
511 if (call_saves_everything_except_r0) {
512 Register temp = locations->GetTemp(0).AsRegister<Register>();
513 bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
514 entry_address = temp_is_r0 ? out : temp;
515 DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
516 if (temp_is_r0) {
517 __ mov(entry_address, ShifterOperand(temp));
518 }
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100519 }
520
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000521 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index.index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000522 arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
523 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100524
525 // Store the resolved String to the .bss entry.
526 if (call_saves_everything_except_r0) {
527 // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
528 __ str(R0, Address(entry_address));
529 } else {
530 // For non-Baker read barrier, we need to re-calculate the address of the string entry.
Vladimir Markoea4c1262017-02-06 19:59:33 +0000531 Register temp = IP;
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100532 CodeGeneratorARM::PcRelativePatchInfo* labels =
533 arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
534 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000535 __ movw(temp, /* placeholder */ 0u);
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100536 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000537 __ movt(temp, /* placeholder */ 0u);
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100538 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000539 __ add(temp, temp, ShifterOperand(PC));
540 __ str(R0, Address(temp));
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100541 }
542
Vladimir Markoaad75c62016-10-03 08:46:48 +0000543 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000544 RestoreLiveRegisters(codegen, locations);
545
Vladimir Markoaad75c62016-10-03 08:46:48 +0000546 __ b(GetExitLabel());
547 }
548
549 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
550
551 private:
552 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
553};
554
Artem Serovf4d6aee2016-07-11 10:41:45 +0100555class TypeCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000556 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000557 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100558 : SlowPathCodeARM(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000559
Alexandre Rames67555f72014-11-18 10:55:16 +0000560 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000561 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000562 DCHECK(instruction_->IsCheckCast()
563 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000564
565 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
566 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000567
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000568 if (!is_fatal_) {
569 SaveLiveRegisters(codegen, locations);
570 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000571
572 // We're moving two locations to locations that could overlap, so we need a parallel
573 // move resolver.
574 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800575 codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800576 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
577 Primitive::kPrimNot,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800578 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800579 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
580 Primitive::kPrimNot);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000581 if (instruction_->IsInstanceOf()) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100582 arm_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100583 instruction_,
584 instruction_->GetDexPc(),
585 this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800586 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000587 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
588 } else {
589 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800590 arm_codegen->InvokeRuntime(kQuickCheckInstanceOf,
591 instruction_,
592 instruction_->GetDexPc(),
593 this);
594 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000595 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000596
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000597 if (!is_fatal_) {
598 RestoreLiveRegisters(codegen, locations);
599 __ b(GetExitLabel());
600 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000601 }
602
Alexandre Rames9931f312015-06-19 14:47:01 +0100603 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
604
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000605 bool IsFatal() const OVERRIDE { return is_fatal_; }
606
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000607 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000608 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000609
610 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
611};
612
Artem Serovf4d6aee2016-07-11 10:41:45 +0100613class DeoptimizationSlowPathARM : public SlowPathCodeARM {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700614 public:
Aart Bik42249c32016-01-07 15:33:50 -0800615 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100616 : SlowPathCodeARM(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700617
618 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800619 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700620 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100621 arm_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000622 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700623 }
624
Alexandre Rames9931f312015-06-19 14:47:01 +0100625 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
626
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700627 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700628 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
629};
630
Artem Serovf4d6aee2016-07-11 10:41:45 +0100631class ArraySetSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100632 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100633 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100634
635 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
636 LocationSummary* locations = instruction_->GetLocations();
637 __ Bind(GetEntryLabel());
638 SaveLiveRegisters(codegen, locations);
639
640 InvokeRuntimeCallingConvention calling_convention;
641 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
642 parallel_move.AddMove(
643 locations->InAt(0),
644 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
645 Primitive::kPrimNot,
646 nullptr);
647 parallel_move.AddMove(
648 locations->InAt(1),
649 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
650 Primitive::kPrimInt,
651 nullptr);
652 parallel_move.AddMove(
653 locations->InAt(2),
654 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
655 Primitive::kPrimNot,
656 nullptr);
657 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
658
659 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100660 arm_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000661 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100662 RestoreLiveRegisters(codegen, locations);
663 __ b(GetExitLabel());
664 }
665
666 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
667
668 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100669 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
670};
671
Roland Levillain54f869e2017-03-06 13:54:11 +0000672// Abstract base class for read barrier slow paths marking a reference
673// `ref`.
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000674//
Roland Levillain54f869e2017-03-06 13:54:11 +0000675// Argument `entrypoint` must be a register location holding the read
676// barrier marking runtime entry point to be invoked.
677class ReadBarrierMarkSlowPathBaseARM : public SlowPathCodeARM {
678 protected:
679 ReadBarrierMarkSlowPathBaseARM(HInstruction* instruction, Location ref, Location entrypoint)
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000680 : SlowPathCodeARM(instruction), ref_(ref), entrypoint_(entrypoint) {
681 DCHECK(kEmitCompilerReadBarrier);
682 }
683
Roland Levillain54f869e2017-03-06 13:54:11 +0000684 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathBaseARM"; }
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000685
Roland Levillain54f869e2017-03-06 13:54:11 +0000686 // Generate assembly code calling the read barrier marking runtime
687 // entry point (ReadBarrierMarkRegX).
688 void GenerateReadBarrierMarkRuntimeCall(CodeGenerator* codegen) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000689 Register ref_reg = ref_.AsRegister<Register>();
Roland Levillain47b3ab22017-02-27 14:31:35 +0000690
Roland Levillain47b3ab22017-02-27 14:31:35 +0000691 // No need to save live registers; it's taken care of by the
692 // entrypoint. Also, there is no need to update the stack mask,
693 // as this runtime call will not trigger a garbage collection.
694 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
695 DCHECK_NE(ref_reg, SP);
696 DCHECK_NE(ref_reg, LR);
697 DCHECK_NE(ref_reg, PC);
698 // IP is used internally by the ReadBarrierMarkRegX entry point
699 // as a temporary, it cannot be the entry point's input/output.
700 DCHECK_NE(ref_reg, IP);
701 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCoreRegisters) << ref_reg;
702 // "Compact" slow path, saving two moves.
703 //
704 // Instead of using the standard runtime calling convention (input
705 // and output in R0):
706 //
707 // R0 <- ref
708 // R0 <- ReadBarrierMark(R0)
709 // ref <- R0
710 //
711 // we just use rX (the register containing `ref`) as input and output
712 // of a dedicated entrypoint:
713 //
714 // rX <- ReadBarrierMarkRegX(rX)
715 //
716 if (entrypoint_.IsValid()) {
717 arm_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
718 __ blx(entrypoint_.AsRegister<Register>());
719 } else {
Roland Levillain54f869e2017-03-06 13:54:11 +0000720 // Entrypoint is not already loaded, load from the thread.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000721 int32_t entry_point_offset =
722 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref_reg);
723 // This runtime call does not require a stack map.
724 arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
725 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000726 }
727
728 // The location (register) of the marked object reference.
729 const Location ref_;
730
731 // The location of the entrypoint if it is already loaded.
732 const Location entrypoint_;
733
734 private:
735 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathBaseARM);
736};
737
Dave Allison20dfc792014-06-16 20:44:29 -0700738// Slow path marking an object reference `ref` during a read
739// barrier. The field `obj.field` in the object `obj` holding this
Roland Levillain54f869e2017-03-06 13:54:11 +0000740// reference does not get updated by this slow path after marking.
Dave Allison20dfc792014-06-16 20:44:29 -0700741//
742// This means that after the execution of this slow path, `ref` will
743// always be up-to-date, but `obj.field` may not; i.e., after the
744// flip, `ref` will be a to-space reference, but `obj.field` will
745// probably still be a from-space reference (unless it gets updated by
746// another thread, or if another thread installed another object
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000747// reference (different from `ref`) in `obj.field`).
748//
749// If `entrypoint` is a valid location it is assumed to already be
750// holding the entrypoint. The case where the entrypoint is passed in
Roland Levillainba650a42017-03-06 13:52:32 +0000751// is when the decision to mark is based on whether the GC is marking.
Roland Levillain54f869e2017-03-06 13:54:11 +0000752class ReadBarrierMarkSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000753 public:
754 ReadBarrierMarkSlowPathARM(HInstruction* instruction,
755 Location ref,
756 Location entrypoint = Location::NoLocation())
Roland Levillain54f869e2017-03-06 13:54:11 +0000757 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000758 DCHECK(kEmitCompilerReadBarrier);
759 }
760
761 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
762
763 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
764 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain54f869e2017-03-06 13:54:11 +0000765 DCHECK(locations->CanCall());
766 if (kIsDebugBuild) {
767 Register ref_reg = ref_.AsRegister<Register>();
768 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
769 }
770 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
771 << "Unexpected instruction in read barrier marking slow path: "
772 << instruction_->DebugName();
773
774 __ Bind(GetEntryLabel());
775 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000776 __ b(GetExitLabel());
777 }
778
779 private:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000780 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
781};
782
Roland Levillain54f869e2017-03-06 13:54:11 +0000783// Slow path loading `obj`'s lock word, loading a reference from
784// object `*(obj + offset + (index << scale_factor))` into `ref`, and
785// marking `ref` if `obj` is gray according to the lock word (Baker
786// read barrier). The field `obj.field` in the object `obj` holding
787// this reference does not get updated by this slow path after marking
788// (see LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
789// below for that).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000790//
Roland Levillain54f869e2017-03-06 13:54:11 +0000791// This means that after the execution of this slow path, `ref` will
792// always be up-to-date, but `obj.field` may not; i.e., after the
793// flip, `ref` will be a to-space reference, but `obj.field` will
794// probably still be a from-space reference (unless it gets updated by
795// another thread, or if another thread installed another object
796// reference (different from `ref`) in `obj.field`).
797//
798// Argument `entrypoint` must be a register location holding the read
799// barrier marking runtime entry point to be invoked.
800class LoadReferenceWithBakerReadBarrierSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000801 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000802 LoadReferenceWithBakerReadBarrierSlowPathARM(HInstruction* instruction,
803 Location ref,
804 Register obj,
805 uint32_t offset,
806 Location index,
807 ScaleFactor scale_factor,
808 bool needs_null_check,
809 Register temp,
810 Location entrypoint)
811 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000812 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000813 offset_(offset),
814 index_(index),
815 scale_factor_(scale_factor),
816 needs_null_check_(needs_null_check),
817 temp_(temp) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000818 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000819 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000820 }
821
Roland Levillain54f869e2017-03-06 13:54:11 +0000822 const char* GetDescription() const OVERRIDE {
823 return "LoadReferenceWithBakerReadBarrierSlowPathARM";
824 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000825
826 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
827 LocationSummary* locations = instruction_->GetLocations();
828 Register ref_reg = ref_.AsRegister<Register>();
829 DCHECK(locations->CanCall());
830 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000831 DCHECK_NE(ref_reg, temp_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000832 DCHECK(instruction_->IsInstanceFieldGet() ||
833 instruction_->IsStaticFieldGet() ||
834 instruction_->IsArrayGet() ||
835 instruction_->IsArraySet() ||
Roland Levillain47b3ab22017-02-27 14:31:35 +0000836 instruction_->IsInstanceOf() ||
837 instruction_->IsCheckCast() ||
838 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
839 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
840 << "Unexpected instruction in read barrier marking slow path: "
841 << instruction_->DebugName();
842 // The read barrier instrumentation of object ArrayGet
843 // instructions does not support the HIntermediateAddress
844 // instruction.
845 DCHECK(!(instruction_->IsArrayGet() &&
846 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
847
848 __ Bind(GetEntryLabel());
Roland Levillain54f869e2017-03-06 13:54:11 +0000849
850 // When using MaybeGenerateReadBarrierSlow, the read barrier call is
851 // inserted after the original load. However, in fast path based
852 // Baker's read barriers, we need to perform the load of
853 // mirror::Object::monitor_ *before* the original reference load.
854 // This load-load ordering is required by the read barrier.
Roland Levillainff487002017-03-07 16:50:01 +0000855 // The slow path (for Baker's algorithm) should look like:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000856 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000857 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
858 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
859 // HeapReference<mirror::Object> ref = *src; // Original reference load.
860 // bool is_gray = (rb_state == ReadBarrier::GrayState());
861 // if (is_gray) {
862 // ref = entrypoint(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
863 // }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000864 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000865 // Note: the original implementation in ReadBarrier::Barrier is
866 // slightly more complex as it performs additional checks that we do
867 // not do here for performance reasons.
868
869 // /* int32_t */ monitor = obj->monitor_
870 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
871 __ LoadFromOffset(kLoadWord, temp_, obj_, monitor_offset);
872 if (needs_null_check_) {
873 codegen->MaybeRecordImplicitNullCheck(instruction_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000874 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000875 // /* LockWord */ lock_word = LockWord(monitor)
876 static_assert(sizeof(LockWord) == sizeof(int32_t),
877 "art::LockWord and int32_t have different sizes.");
878
879 // Introduce a dependency on the lock_word including the rb_state,
880 // which shall prevent load-load reordering without using
881 // a memory barrier (which would be more expensive).
882 // `obj` is unchanged by this operation, but its value now depends
883 // on `temp`.
884 __ add(obj_, obj_, ShifterOperand(temp_, LSR, 32));
885
886 // The actual reference load.
887 // A possible implicit null check has already been handled above.
888 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
889 arm_codegen->GenerateRawReferenceLoad(
890 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
891
892 // Mark the object `ref` when `obj` is gray.
893 //
894 // if (rb_state == ReadBarrier::GrayState())
895 // ref = ReadBarrier::Mark(ref);
896 //
897 // Given the numeric representation, it's enough to check the low bit of the
898 // rb_state. We do that by shifting the bit out of the lock word with LSRS
899 // which can be a 16-bit instruction unlike the TST immediate.
900 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
901 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
902 __ Lsrs(temp_, temp_, LockWord::kReadBarrierStateShift + 1);
903 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
904 GenerateReadBarrierMarkRuntimeCall(codegen);
905
Roland Levillain47b3ab22017-02-27 14:31:35 +0000906 __ b(GetExitLabel());
907 }
908
909 private:
Roland Levillain54f869e2017-03-06 13:54:11 +0000910 // The register containing the object holding the marked object reference field.
911 Register obj_;
912 // The offset, index and scale factor to access the reference in `obj_`.
913 uint32_t offset_;
914 Location index_;
915 ScaleFactor scale_factor_;
916 // Is a null check required?
917 bool needs_null_check_;
918 // A temporary register used to hold the lock word of `obj_`.
919 Register temp_;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000920
Roland Levillain54f869e2017-03-06 13:54:11 +0000921 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierSlowPathARM);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000922};
923
Roland Levillain54f869e2017-03-06 13:54:11 +0000924// Slow path loading `obj`'s lock word, loading a reference from
925// object `*(obj + offset + (index << scale_factor))` into `ref`, and
926// marking `ref` if `obj` is gray according to the lock word (Baker
927// read barrier). If needed, this slow path also atomically updates
928// the field `obj.field` in the object `obj` holding this reference
929// after marking (contrary to
930// LoadReferenceWithBakerReadBarrierSlowPathARM above, which never
931// tries to update `obj.field`).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000932//
933// This means that after the execution of this slow path, both `ref`
934// and `obj.field` will be up-to-date; i.e., after the flip, both will
935// hold the same to-space reference (unless another thread installed
936// another object reference (different from `ref`) in `obj.field`).
Roland Levillainba650a42017-03-06 13:52:32 +0000937//
Roland Levillain54f869e2017-03-06 13:54:11 +0000938// Argument `entrypoint` must be a register location holding the read
939// barrier marking runtime entry point to be invoked.
940class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
941 : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000942 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000943 LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(HInstruction* instruction,
944 Location ref,
945 Register obj,
946 uint32_t offset,
947 Location index,
948 ScaleFactor scale_factor,
949 bool needs_null_check,
950 Register temp1,
951 Register temp2,
952 Location entrypoint)
953 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000954 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000955 offset_(offset),
956 index_(index),
957 scale_factor_(scale_factor),
958 needs_null_check_(needs_null_check),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000959 temp1_(temp1),
Roland Levillain54f869e2017-03-06 13:54:11 +0000960 temp2_(temp2) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000961 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000962 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000963 }
964
Roland Levillain54f869e2017-03-06 13:54:11 +0000965 const char* GetDescription() const OVERRIDE {
966 return "LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM";
967 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000968
969 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
970 LocationSummary* locations = instruction_->GetLocations();
971 Register ref_reg = ref_.AsRegister<Register>();
972 DCHECK(locations->CanCall());
973 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000974 DCHECK_NE(ref_reg, temp1_);
975
976 // This slow path is only used by the UnsafeCASObject intrinsic at the moment.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000977 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
978 << "Unexpected instruction in read barrier marking and field updating slow path: "
979 << instruction_->DebugName();
980 DCHECK(instruction_->GetLocations()->Intrinsified());
981 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
Roland Levillain54f869e2017-03-06 13:54:11 +0000982 DCHECK_EQ(offset_, 0u);
983 DCHECK_EQ(scale_factor_, ScaleFactor::TIMES_1);
984 // The location of the offset of the marked reference field within `obj_`.
985 Location field_offset = index_;
986 DCHECK(field_offset.IsRegisterPair()) << field_offset;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000987
988 __ Bind(GetEntryLabel());
989
Roland Levillainff487002017-03-07 16:50:01 +0000990 // The implementation is similar to LoadReferenceWithBakerReadBarrierSlowPathARM's:
991 //
992 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
993 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
994 // HeapReference<mirror::Object> ref = *src; // Original reference load.
995 // bool is_gray = (rb_state == ReadBarrier::GrayState());
996 // if (is_gray) {
997 // old_ref = ref;
998 // ref = entrypoint(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
999 // compareAndSwapObject(obj, field_offset, old_ref, ref);
1000 // }
1001
Roland Levillain54f869e2017-03-06 13:54:11 +00001002 // /* int32_t */ monitor = obj->monitor_
1003 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
1004 __ LoadFromOffset(kLoadWord, temp1_, obj_, monitor_offset);
1005 if (needs_null_check_) {
1006 codegen->MaybeRecordImplicitNullCheck(instruction_);
1007 }
1008 // /* LockWord */ lock_word = LockWord(monitor)
1009 static_assert(sizeof(LockWord) == sizeof(int32_t),
1010 "art::LockWord and int32_t have different sizes.");
1011
1012 // Introduce a dependency on the lock_word including the rb_state,
1013 // which shall prevent load-load reordering without using
1014 // a memory barrier (which would be more expensive).
1015 // `obj` is unchanged by this operation, but its value now depends
1016 // on `temp1`.
1017 __ add(obj_, obj_, ShifterOperand(temp1_, LSR, 32));
1018
1019 // The actual reference load.
1020 // A possible implicit null check has already been handled above.
1021 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1022 arm_codegen->GenerateRawReferenceLoad(
1023 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
1024
1025 // Mark the object `ref` when `obj` is gray.
1026 //
1027 // if (rb_state == ReadBarrier::GrayState())
1028 // ref = ReadBarrier::Mark(ref);
1029 //
1030 // Given the numeric representation, it's enough to check the low bit of the
1031 // rb_state. We do that by shifting the bit out of the lock word with LSRS
1032 // which can be a 16-bit instruction unlike the TST immediate.
1033 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
1034 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
1035 __ Lsrs(temp1_, temp1_, LockWord::kReadBarrierStateShift + 1);
1036 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
1037
1038 // Save the old value of the reference before marking it.
Roland Levillain47b3ab22017-02-27 14:31:35 +00001039 // Note that we cannot use IP to save the old reference, as IP is
1040 // used internally by the ReadBarrierMarkRegX entry point, and we
1041 // need the old reference after the call to that entry point.
1042 DCHECK_NE(temp1_, IP);
1043 __ Mov(temp1_, ref_reg);
Roland Levillain27b1f9c2017-01-17 16:56:34 +00001044
Roland Levillain54f869e2017-03-06 13:54:11 +00001045 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001046
1047 // If the new reference is different from the old reference,
Roland Levillain54f869e2017-03-06 13:54:11 +00001048 // update the field in the holder (`*(obj_ + field_offset)`).
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001049 //
1050 // Note that this field could also hold a different object, if
1051 // another thread had concurrently changed it. In that case, the
1052 // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set
1053 // (CAS) operation below would abort the CAS, leaving the field
1054 // as-is.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001055 __ cmp(temp1_, ShifterOperand(ref_reg));
Roland Levillain54f869e2017-03-06 13:54:11 +00001056 __ b(GetExitLabel(), EQ);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001057
1058 // Update the the holder's field atomically. This may fail if
1059 // mutator updates before us, but it's OK. This is achieved
1060 // using a strong compare-and-set (CAS) operation with relaxed
1061 // memory synchronization ordering, where the expected value is
1062 // the old reference and the desired value is the new reference.
1063
1064 // Convenience aliases.
1065 Register base = obj_;
1066 // The UnsafeCASObject intrinsic uses a register pair as field
1067 // offset ("long offset"), of which only the low part contains
1068 // data.
Roland Levillain54f869e2017-03-06 13:54:11 +00001069 Register offset = field_offset.AsRegisterPairLow<Register>();
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001070 Register expected = temp1_;
1071 Register value = ref_reg;
1072 Register tmp_ptr = IP; // Pointer to actual memory.
1073 Register tmp = temp2_; // Value in memory.
1074
1075 __ add(tmp_ptr, base, ShifterOperand(offset));
1076
1077 if (kPoisonHeapReferences) {
1078 __ PoisonHeapReference(expected);
1079 if (value == expected) {
1080 // Do not poison `value`, as it is the same register as
1081 // `expected`, which has just been poisoned.
1082 } else {
1083 __ PoisonHeapReference(value);
1084 }
1085 }
1086
1087 // do {
1088 // tmp = [r_ptr] - expected;
1089 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
1090
Roland Levillain24a4d112016-10-26 13:10:46 +01001091 Label loop_head, exit_loop;
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001092 __ Bind(&loop_head);
1093
1094 __ ldrex(tmp, tmp_ptr);
1095
1096 __ subs(tmp, tmp, ShifterOperand(expected));
1097
Roland Levillain24a4d112016-10-26 13:10:46 +01001098 __ it(NE);
1099 __ clrex(NE);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001100
Roland Levillain24a4d112016-10-26 13:10:46 +01001101 __ b(&exit_loop, NE);
1102
1103 __ strex(tmp, value, tmp_ptr);
1104 __ cmp(tmp, ShifterOperand(1));
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001105 __ b(&loop_head, EQ);
1106
Roland Levillain24a4d112016-10-26 13:10:46 +01001107 __ Bind(&exit_loop);
1108
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001109 if (kPoisonHeapReferences) {
1110 __ UnpoisonHeapReference(expected);
1111 if (value == expected) {
1112 // Do not unpoison `value`, as it is the same register as
1113 // `expected`, which has just been unpoisoned.
1114 } else {
1115 __ UnpoisonHeapReference(value);
1116 }
1117 }
1118
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001119 __ b(GetExitLabel());
1120 }
1121
1122 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001123 // The register containing the object holding the marked object reference field.
1124 const Register obj_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001125 // The offset, index and scale factor to access the reference in `obj_`.
1126 uint32_t offset_;
1127 Location index_;
1128 ScaleFactor scale_factor_;
1129 // Is a null check required?
1130 bool needs_null_check_;
1131 // A temporary register used to hold the lock word of `obj_`; and
1132 // also to hold the original reference value, when the reference is
1133 // marked.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001134 const Register temp1_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001135 // A temporary register used in the implementation of the CAS, to
1136 // update the object's reference field.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001137 const Register temp2_;
1138
Roland Levillain54f869e2017-03-06 13:54:11 +00001139 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001140};
1141
Roland Levillain3b359c72015-11-17 19:35:12 +00001142// Slow path generating a read barrier for a heap reference.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001143class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001144 public:
1145 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
1146 Location out,
1147 Location ref,
1148 Location obj,
1149 uint32_t offset,
1150 Location index)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001151 : SlowPathCodeARM(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +00001152 out_(out),
1153 ref_(ref),
1154 obj_(obj),
1155 offset_(offset),
1156 index_(index) {
1157 DCHECK(kEmitCompilerReadBarrier);
1158 // If `obj` is equal to `out` or `ref`, it means the initial object
1159 // has been overwritten by (or after) the heap object reference load
1160 // to be instrumented, e.g.:
1161 //
1162 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00001163 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001164 //
1165 // In that case, we have lost the information about the original
1166 // object, and the emitted read barrier cannot work properly.
1167 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
1168 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
1169 }
1170
1171 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1172 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1173 LocationSummary* locations = instruction_->GetLocations();
1174 Register reg_out = out_.AsRegister<Register>();
1175 DCHECK(locations->CanCall());
1176 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +01001177 DCHECK(instruction_->IsInstanceFieldGet() ||
1178 instruction_->IsStaticFieldGet() ||
1179 instruction_->IsArrayGet() ||
1180 instruction_->IsInstanceOf() ||
1181 instruction_->IsCheckCast() ||
Andreas Gamped9911ee2017-03-27 13:27:24 -07001182 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
Roland Levillainc9285912015-12-18 10:38:42 +00001183 << "Unexpected instruction in read barrier for heap reference slow path: "
1184 << instruction_->DebugName();
Roland Levillain19c54192016-11-04 13:44:09 +00001185 // The read barrier instrumentation of object ArrayGet
1186 // instructions does not support the HIntermediateAddress
1187 // instruction.
1188 DCHECK(!(instruction_->IsArrayGet() &&
1189 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
Roland Levillain3b359c72015-11-17 19:35:12 +00001190
1191 __ Bind(GetEntryLabel());
1192 SaveLiveRegisters(codegen, locations);
1193
1194 // We may have to change the index's value, but as `index_` is a
1195 // constant member (like other "inputs" of this slow path),
1196 // introduce a copy of it, `index`.
1197 Location index = index_;
1198 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +01001199 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +00001200 if (instruction_->IsArrayGet()) {
1201 // Compute the actual memory offset and store it in `index`.
1202 Register index_reg = index_.AsRegister<Register>();
1203 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
1204 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
1205 // We are about to change the value of `index_reg` (see the
1206 // calls to art::arm::Thumb2Assembler::Lsl and
1207 // art::arm::Thumb2Assembler::AddConstant below), but it has
1208 // not been saved by the previous call to
1209 // art::SlowPathCode::SaveLiveRegisters, as it is a
1210 // callee-save register --
1211 // art::SlowPathCode::SaveLiveRegisters does not consider
1212 // callee-save registers, as it has been designed with the
1213 // assumption that callee-save registers are supposed to be
1214 // handled by the called function. So, as a callee-save
1215 // register, `index_reg` _would_ eventually be saved onto
1216 // the stack, but it would be too late: we would have
1217 // changed its value earlier. Therefore, we manually save
1218 // it here into another freely available register,
1219 // `free_reg`, chosen of course among the caller-save
1220 // registers (as a callee-save `free_reg` register would
1221 // exhibit the same problem).
1222 //
1223 // Note we could have requested a temporary register from
1224 // the register allocator instead; but we prefer not to, as
1225 // this is a slow path, and we know we can find a
1226 // caller-save register that is available.
1227 Register free_reg = FindAvailableCallerSaveRegister(codegen);
1228 __ Mov(free_reg, index_reg);
1229 index_reg = free_reg;
1230 index = Location::RegisterLocation(index_reg);
1231 } else {
1232 // The initial register stored in `index_` has already been
1233 // saved in the call to art::SlowPathCode::SaveLiveRegisters
1234 // (as it is not a callee-save register), so we can freely
1235 // use it.
1236 }
1237 // Shifting the index value contained in `index_reg` by the scale
1238 // factor (2) cannot overflow in practice, as the runtime is
1239 // unable to allocate object arrays with a size larger than
1240 // 2^26 - 1 (that is, 2^28 - 4 bytes).
1241 __ Lsl(index_reg, index_reg, TIMES_4);
1242 static_assert(
1243 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
1244 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
1245 __ AddConstant(index_reg, index_reg, offset_);
1246 } else {
Roland Levillain3d312422016-06-23 13:53:42 +01001247 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
1248 // intrinsics, `index_` is not shifted by a scale factor of 2
1249 // (as in the case of ArrayGet), as it is actually an offset
1250 // to an object field within an object.
1251 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001252 DCHECK(instruction_->GetLocations()->Intrinsified());
1253 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
1254 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
1255 << instruction_->AsInvoke()->GetIntrinsic();
1256 DCHECK_EQ(offset_, 0U);
1257 DCHECK(index_.IsRegisterPair());
1258 // UnsafeGet's offset location is a register pair, the low
1259 // part contains the correct offset.
1260 index = index_.ToLow();
1261 }
1262 }
1263
1264 // We're moving two or three locations to locations that could
1265 // overlap, so we need a parallel move resolver.
1266 InvokeRuntimeCallingConvention calling_convention;
1267 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
1268 parallel_move.AddMove(ref_,
1269 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
1270 Primitive::kPrimNot,
1271 nullptr);
1272 parallel_move.AddMove(obj_,
1273 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
1274 Primitive::kPrimNot,
1275 nullptr);
1276 if (index.IsValid()) {
1277 parallel_move.AddMove(index,
1278 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
1279 Primitive::kPrimInt,
1280 nullptr);
1281 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1282 } else {
1283 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1284 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
1285 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001286 arm_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
Roland Levillain3b359c72015-11-17 19:35:12 +00001287 CheckEntrypointTypes<
1288 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
1289 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1290
1291 RestoreLiveRegisters(codegen, locations);
1292 __ b(GetExitLabel());
1293 }
1294
1295 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
1296
1297 private:
1298 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
1299 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
1300 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
1301 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
1302 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
1303 return static_cast<Register>(i);
1304 }
1305 }
1306 // We shall never fail to find a free caller-save register, as
1307 // there are more than two core caller-save registers on ARM
1308 // (meaning it is possible to find one which is different from
1309 // `ref` and `obj`).
1310 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
1311 LOG(FATAL) << "Could not find a free caller-save register";
1312 UNREACHABLE();
1313 }
1314
Roland Levillain3b359c72015-11-17 19:35:12 +00001315 const Location out_;
1316 const Location ref_;
1317 const Location obj_;
1318 const uint32_t offset_;
1319 // An additional location containing an index to an array.
1320 // Only used for HArrayGet and the UnsafeGetObject &
1321 // UnsafeGetObjectVolatile intrinsics.
1322 const Location index_;
1323
1324 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
1325};
1326
1327// Slow path generating a read barrier for a GC root.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001328class ReadBarrierForRootSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001329 public:
1330 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001331 : SlowPathCodeARM(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +00001332 DCHECK(kEmitCompilerReadBarrier);
1333 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001334
1335 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1336 LocationSummary* locations = instruction_->GetLocations();
1337 Register reg_out = out_.AsRegister<Register>();
1338 DCHECK(locations->CanCall());
1339 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +00001340 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
1341 << "Unexpected instruction in read barrier for GC root slow path: "
1342 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001343
1344 __ Bind(GetEntryLabel());
1345 SaveLiveRegisters(codegen, locations);
1346
1347 InvokeRuntimeCallingConvention calling_convention;
1348 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1349 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001350 arm_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain3b359c72015-11-17 19:35:12 +00001351 instruction_,
1352 instruction_->GetDexPc(),
1353 this);
1354 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
1355 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1356
1357 RestoreLiveRegisters(codegen, locations);
1358 __ b(GetExitLabel());
1359 }
1360
1361 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
1362
1363 private:
Roland Levillain3b359c72015-11-17 19:35:12 +00001364 const Location out_;
1365 const Location root_;
1366
1367 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
1368};
1369
Aart Bike9f37602015-10-09 11:15:55 -07001370inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001371 switch (cond) {
1372 case kCondEQ: return EQ;
1373 case kCondNE: return NE;
1374 case kCondLT: return LT;
1375 case kCondLE: return LE;
1376 case kCondGT: return GT;
1377 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -07001378 case kCondB: return LO;
1379 case kCondBE: return LS;
1380 case kCondA: return HI;
1381 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001382 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001383 LOG(FATAL) << "Unreachable";
1384 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001385}
1386
Aart Bike9f37602015-10-09 11:15:55 -07001387// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001388inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001389 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001390 case kCondEQ: return EQ;
1391 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -07001392 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001393 case kCondLT: return LO;
1394 case kCondLE: return LS;
1395 case kCondGT: return HI;
1396 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -07001397 // Unsigned remain unchanged.
1398 case kCondB: return LO;
1399 case kCondBE: return LS;
1400 case kCondA: return HI;
1401 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001402 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001403 LOG(FATAL) << "Unreachable";
1404 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001405}
1406
Vladimir Markod6e069b2016-01-18 11:11:01 +00001407inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
1408 // The ARM condition codes can express all the necessary branches, see the
1409 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
1410 // There is no dex instruction or HIR that would need the missing conditions
1411 // "equal or unordered" or "not equal".
1412 switch (cond) {
1413 case kCondEQ: return EQ;
1414 case kCondNE: return NE /* unordered */;
1415 case kCondLT: return gt_bias ? CC : LT /* unordered */;
1416 case kCondLE: return gt_bias ? LS : LE /* unordered */;
1417 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
1418 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
1419 default:
1420 LOG(FATAL) << "UNREACHABLE";
1421 UNREACHABLE();
1422 }
1423}
1424
Anton Kirilov74234da2017-01-13 14:42:47 +00001425inline Shift ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
1426 switch (op_kind) {
1427 case HDataProcWithShifterOp::kASR: return ASR;
1428 case HDataProcWithShifterOp::kLSL: return LSL;
1429 case HDataProcWithShifterOp::kLSR: return LSR;
1430 default:
1431 LOG(FATAL) << "Unexpected op kind " << op_kind;
1432 UNREACHABLE();
1433 }
1434}
1435
1436static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
1437 Register out,
1438 Register first,
1439 const ShifterOperand& second,
1440 CodeGeneratorARM* codegen) {
1441 if (second.IsImmediate() && second.GetImmediate() == 0) {
1442 const ShifterOperand in = kind == HInstruction::kAnd
1443 ? ShifterOperand(0)
1444 : ShifterOperand(first);
1445
1446 __ mov(out, in);
1447 } else {
1448 switch (kind) {
1449 case HInstruction::kAdd:
1450 __ add(out, first, second);
1451 break;
1452 case HInstruction::kAnd:
1453 __ and_(out, first, second);
1454 break;
1455 case HInstruction::kOr:
1456 __ orr(out, first, second);
1457 break;
1458 case HInstruction::kSub:
1459 __ sub(out, first, second);
1460 break;
1461 case HInstruction::kXor:
1462 __ eor(out, first, second);
1463 break;
1464 default:
1465 LOG(FATAL) << "Unexpected instruction kind: " << kind;
1466 UNREACHABLE();
1467 }
1468 }
1469}
1470
1471static void GenerateDataProc(HInstruction::InstructionKind kind,
1472 const Location& out,
1473 const Location& first,
1474 const ShifterOperand& second_lo,
1475 const ShifterOperand& second_hi,
1476 CodeGeneratorARM* codegen) {
1477 const Register first_hi = first.AsRegisterPairHigh<Register>();
1478 const Register first_lo = first.AsRegisterPairLow<Register>();
1479 const Register out_hi = out.AsRegisterPairHigh<Register>();
1480 const Register out_lo = out.AsRegisterPairLow<Register>();
1481
1482 if (kind == HInstruction::kAdd) {
1483 __ adds(out_lo, first_lo, second_lo);
1484 __ adc(out_hi, first_hi, second_hi);
1485 } else if (kind == HInstruction::kSub) {
1486 __ subs(out_lo, first_lo, second_lo);
1487 __ sbc(out_hi, first_hi, second_hi);
1488 } else {
1489 GenerateDataProcInstruction(kind, out_lo, first_lo, second_lo, codegen);
1490 GenerateDataProcInstruction(kind, out_hi, first_hi, second_hi, codegen);
1491 }
1492}
1493
1494static ShifterOperand GetShifterOperand(Register rm, Shift shift, uint32_t shift_imm) {
1495 return shift_imm == 0 ? ShifterOperand(rm) : ShifterOperand(rm, shift, shift_imm);
1496}
1497
1498static void GenerateLongDataProc(HDataProcWithShifterOp* instruction, CodeGeneratorARM* codegen) {
1499 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
1500 DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
1501
1502 const LocationSummary* const locations = instruction->GetLocations();
1503 const uint32_t shift_value = instruction->GetShiftAmount();
1504 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
1505 const Location first = locations->InAt(0);
1506 const Location second = locations->InAt(1);
1507 const Location out = locations->Out();
1508 const Register first_hi = first.AsRegisterPairHigh<Register>();
1509 const Register first_lo = first.AsRegisterPairLow<Register>();
1510 const Register out_hi = out.AsRegisterPairHigh<Register>();
1511 const Register out_lo = out.AsRegisterPairLow<Register>();
1512 const Register second_hi = second.AsRegisterPairHigh<Register>();
1513 const Register second_lo = second.AsRegisterPairLow<Register>();
1514 const Shift shift = ShiftFromOpKind(instruction->GetOpKind());
1515
1516 if (shift_value >= 32) {
1517 if (shift == LSL) {
1518 GenerateDataProcInstruction(kind,
1519 out_hi,
1520 first_hi,
1521 ShifterOperand(second_lo, LSL, shift_value - 32),
1522 codegen);
1523 GenerateDataProcInstruction(kind,
1524 out_lo,
1525 first_lo,
1526 ShifterOperand(0),
1527 codegen);
1528 } else if (shift == ASR) {
1529 GenerateDataProc(kind,
1530 out,
1531 first,
1532 GetShifterOperand(second_hi, ASR, shift_value - 32),
1533 ShifterOperand(second_hi, ASR, 31),
1534 codegen);
1535 } else {
1536 DCHECK_EQ(shift, LSR);
1537 GenerateDataProc(kind,
1538 out,
1539 first,
1540 GetShifterOperand(second_hi, LSR, shift_value - 32),
1541 ShifterOperand(0),
1542 codegen);
1543 }
1544 } else {
1545 DCHECK_GT(shift_value, 1U);
1546 DCHECK_LT(shift_value, 32U);
1547
1548 if (shift == LSL) {
1549 // We are not doing this for HInstruction::kAdd because the output will require
1550 // Location::kOutputOverlap; not applicable to other cases.
1551 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1552 GenerateDataProcInstruction(kind,
1553 out_hi,
1554 first_hi,
1555 ShifterOperand(second_hi, LSL, shift_value),
1556 codegen);
1557 GenerateDataProcInstruction(kind,
1558 out_hi,
1559 out_hi,
1560 ShifterOperand(second_lo, LSR, 32 - shift_value),
1561 codegen);
1562 GenerateDataProcInstruction(kind,
1563 out_lo,
1564 first_lo,
1565 ShifterOperand(second_lo, LSL, shift_value),
1566 codegen);
1567 } else {
1568 __ Lsl(IP, second_hi, shift_value);
1569 __ orr(IP, IP, ShifterOperand(second_lo, LSR, 32 - shift_value));
1570 GenerateDataProc(kind,
1571 out,
1572 first,
1573 ShifterOperand(second_lo, LSL, shift_value),
1574 ShifterOperand(IP),
1575 codegen);
1576 }
1577 } else {
1578 DCHECK(shift == ASR || shift == LSR);
1579
1580 // We are not doing this for HInstruction::kAdd because the output will require
1581 // Location::kOutputOverlap; not applicable to other cases.
1582 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1583 GenerateDataProcInstruction(kind,
1584 out_lo,
1585 first_lo,
1586 ShifterOperand(second_lo, LSR, shift_value),
1587 codegen);
1588 GenerateDataProcInstruction(kind,
1589 out_lo,
1590 out_lo,
1591 ShifterOperand(second_hi, LSL, 32 - shift_value),
1592 codegen);
1593 GenerateDataProcInstruction(kind,
1594 out_hi,
1595 first_hi,
1596 ShifterOperand(second_hi, shift, shift_value),
1597 codegen);
1598 } else {
1599 __ Lsr(IP, second_lo, shift_value);
1600 __ orr(IP, IP, ShifterOperand(second_hi, LSL, 32 - shift_value));
1601 GenerateDataProc(kind,
1602 out,
1603 first,
1604 ShifterOperand(IP),
1605 ShifterOperand(second_hi, shift, shift_value),
1606 codegen);
1607 }
1608 }
1609 }
1610}
1611
Donghui Bai426b49c2016-11-08 14:55:38 +08001612static void GenerateVcmp(HInstruction* instruction, CodeGeneratorARM* codegen) {
1613 Primitive::Type type = instruction->InputAt(0)->GetType();
1614 Location lhs_loc = instruction->GetLocations()->InAt(0);
1615 Location rhs_loc = instruction->GetLocations()->InAt(1);
1616 if (rhs_loc.IsConstant()) {
1617 // 0.0 is the only immediate that can be encoded directly in
1618 // a VCMP instruction.
1619 //
1620 // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
1621 // specify that in a floating-point comparison, positive zero
1622 // and negative zero are considered equal, so we can use the
1623 // literal 0.0 for both cases here.
1624 //
1625 // Note however that some methods (Float.equal, Float.compare,
1626 // Float.compareTo, Double.equal, Double.compare,
1627 // Double.compareTo, Math.max, Math.min, StrictMath.max,
1628 // StrictMath.min) consider 0.0 to be (strictly) greater than
1629 // -0.0. So if we ever translate calls to these methods into a
1630 // HCompare instruction, we must handle the -0.0 case with
1631 // care here.
1632 DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
1633 if (type == Primitive::kPrimFloat) {
1634 __ vcmpsz(lhs_loc.AsFpuRegister<SRegister>());
1635 } else {
1636 DCHECK_EQ(type, Primitive::kPrimDouble);
1637 __ vcmpdz(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()));
1638 }
1639 } else {
1640 if (type == Primitive::kPrimFloat) {
1641 __ vcmps(lhs_loc.AsFpuRegister<SRegister>(), rhs_loc.AsFpuRegister<SRegister>());
1642 } else {
1643 DCHECK_EQ(type, Primitive::kPrimDouble);
1644 __ vcmpd(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()),
1645 FromLowSToD(rhs_loc.AsFpuRegisterPairLow<SRegister>()));
1646 }
1647 }
1648}
1649
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001650static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* condition,
1651 bool invert,
1652 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001653 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1654
1655 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001656 IfCondition cond = condition->GetCondition();
1657 IfCondition opposite = condition->GetOppositeCondition();
1658
1659 if (invert) {
1660 std::swap(cond, opposite);
1661 }
1662
1663 std::pair<Condition, Condition> ret;
Donghui Bai426b49c2016-11-08 14:55:38 +08001664 const Location left = locations->InAt(0);
1665 const Location right = locations->InAt(1);
1666
1667 DCHECK(right.IsConstant());
1668
1669 const Register left_high = left.AsRegisterPairHigh<Register>();
1670 const Register left_low = left.AsRegisterPairLow<Register>();
1671 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1672
1673 switch (cond) {
1674 case kCondEQ:
1675 case kCondNE:
1676 case kCondB:
1677 case kCondBE:
1678 case kCondA:
1679 case kCondAE:
1680 __ CmpConstant(left_high, High32Bits(value));
1681 __ it(EQ);
1682 __ cmp(left_low, ShifterOperand(Low32Bits(value)), EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001683 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001684 break;
1685 case kCondLE:
1686 case kCondGT:
1687 // Trivially true or false.
1688 if (value == std::numeric_limits<int64_t>::max()) {
1689 __ cmp(left_low, ShifterOperand(left_low));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001690 ret = cond == kCondLE ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
Donghui Bai426b49c2016-11-08 14:55:38 +08001691 break;
1692 }
1693
1694 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001695 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001696 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001697 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001698 } else {
1699 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001700 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001701 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001702 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001703 }
1704
1705 value++;
1706 FALLTHROUGH_INTENDED;
1707 case kCondGE:
1708 case kCondLT:
1709 __ CmpConstant(left_low, Low32Bits(value));
1710 __ sbcs(IP, left_high, ShifterOperand(High32Bits(value)));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001711 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001712 break;
1713 default:
1714 LOG(FATAL) << "Unreachable";
1715 UNREACHABLE();
1716 }
1717
1718 return ret;
1719}
1720
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001721static std::pair<Condition, Condition> GenerateLongTest(HCondition* condition,
1722 bool invert,
1723 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001724 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1725
1726 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001727 IfCondition cond = condition->GetCondition();
1728 IfCondition opposite = condition->GetOppositeCondition();
1729
1730 if (invert) {
1731 std::swap(cond, opposite);
1732 }
1733
1734 std::pair<Condition, Condition> ret;
Donghui Bai426b49c2016-11-08 14:55:38 +08001735 Location left = locations->InAt(0);
1736 Location right = locations->InAt(1);
1737
1738 DCHECK(right.IsRegisterPair());
1739
1740 switch (cond) {
1741 case kCondEQ:
1742 case kCondNE:
1743 case kCondB:
1744 case kCondBE:
1745 case kCondA:
1746 case kCondAE:
1747 __ cmp(left.AsRegisterPairHigh<Register>(),
1748 ShifterOperand(right.AsRegisterPairHigh<Register>()));
1749 __ it(EQ);
1750 __ cmp(left.AsRegisterPairLow<Register>(),
1751 ShifterOperand(right.AsRegisterPairLow<Register>()),
1752 EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001753 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001754 break;
1755 case kCondLE:
1756 case kCondGT:
1757 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001758 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001759 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001760 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001761 } else {
1762 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001763 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001764 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001765 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001766 }
1767
1768 std::swap(left, right);
1769 FALLTHROUGH_INTENDED;
1770 case kCondGE:
1771 case kCondLT:
1772 __ cmp(left.AsRegisterPairLow<Register>(),
1773 ShifterOperand(right.AsRegisterPairLow<Register>()));
1774 __ sbcs(IP,
1775 left.AsRegisterPairHigh<Register>(),
1776 ShifterOperand(right.AsRegisterPairHigh<Register>()));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001777 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001778 break;
1779 default:
1780 LOG(FATAL) << "Unreachable";
1781 UNREACHABLE();
1782 }
1783
1784 return ret;
1785}
1786
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001787static std::pair<Condition, Condition> GenerateTest(HCondition* condition,
1788 bool invert,
1789 CodeGeneratorARM* codegen) {
1790 const LocationSummary* const locations = condition->GetLocations();
1791 const Primitive::Type type = condition->GetLeft()->GetType();
1792 IfCondition cond = condition->GetCondition();
1793 IfCondition opposite = condition->GetOppositeCondition();
1794 std::pair<Condition, Condition> ret;
1795 const Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08001796
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001797 if (invert) {
1798 std::swap(cond, opposite);
1799 }
Donghui Bai426b49c2016-11-08 14:55:38 +08001800
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001801 if (type == Primitive::kPrimLong) {
1802 ret = locations->InAt(1).IsConstant()
1803 ? GenerateLongTestConstant(condition, invert, codegen)
1804 : GenerateLongTest(condition, invert, codegen);
1805 } else if (Primitive::IsFloatingPointType(type)) {
1806 GenerateVcmp(condition, codegen);
1807 __ vmstat();
1808 ret = std::make_pair(ARMFPCondition(cond, condition->IsGtBias()),
1809 ARMFPCondition(opposite, condition->IsGtBias()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001810 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001811 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
Donghui Bai426b49c2016-11-08 14:55:38 +08001812
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001813 const Register left = locations->InAt(0).AsRegister<Register>();
1814
1815 if (right.IsRegister()) {
1816 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001817 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001818 DCHECK(right.IsConstant());
1819 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001820 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001821
1822 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001823 }
1824
1825 return ret;
1826}
1827
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001828static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) {
1829 if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
1830 const LocationSummary* const locations = condition->GetLocations();
1831 const IfCondition c = condition->GetCondition();
Donghui Bai426b49c2016-11-08 14:55:38 +08001832
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001833 if (locations->InAt(1).IsConstant()) {
1834 const int64_t value = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue();
1835 ShifterOperand so;
Donghui Bai426b49c2016-11-08 14:55:38 +08001836
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001837 if (c < kCondLT || c > kCondGE) {
1838 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1839 // we check that the least significant half of the first input to be compared
1840 // is in a low register (the other half is read outside an IT block), and
1841 // the constant fits in an 8-bit unsigned integer, so that a 16-bit CMP
1842 // encoding can be used.
1843 if (!ArmAssembler::IsLowRegister(locations->InAt(0).AsRegisterPairLow<Register>()) ||
1844 !IsUint<8>(Low32Bits(value))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001845 return false;
1846 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001847 } else if (c == kCondLE || c == kCondGT) {
1848 if (value < std::numeric_limits<int64_t>::max() &&
1849 !assembler->ShifterOperandCanHold(kNoRegister,
1850 kNoRegister,
1851 SBC,
1852 High32Bits(value + 1),
1853 kCcSet,
1854 &so)) {
1855 return false;
1856 }
1857 } else if (!assembler->ShifterOperandCanHold(kNoRegister,
1858 kNoRegister,
1859 SBC,
1860 High32Bits(value),
1861 kCcSet,
1862 &so)) {
1863 return false;
Donghui Bai426b49c2016-11-08 14:55:38 +08001864 }
1865 }
1866 }
1867
1868 return true;
1869}
1870
1871static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) {
1872 const Primitive::Type type = constant->GetType();
1873 bool ret = false;
1874
1875 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
1876
1877 if (type == Primitive::kPrimLong) {
1878 const uint64_t value = constant->AsLongConstant()->GetValueAsUint64();
1879
1880 ret = IsUint<8>(Low32Bits(value)) && IsUint<8>(High32Bits(value));
1881 } else {
1882 ret = IsUint<8>(CodeGenerator::GetInt32ValueOf(constant));
1883 }
1884
1885 return ret;
1886}
1887
1888static Location Arm8BitEncodableConstantOrRegister(HInstruction* constant) {
1889 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
1890
1891 if (constant->IsConstant() && CanEncodeConstantAs8BitImmediate(constant->AsConstant())) {
1892 return Location::ConstantLocation(constant->AsConstant());
1893 }
1894
1895 return Location::RequiresRegister();
1896}
1897
1898static bool CanGenerateConditionalMove(const Location& out, const Location& src) {
1899 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1900 // we check that we are not dealing with floating-point output (there is no
1901 // 16-bit VMOV encoding).
1902 if (!out.IsRegister() && !out.IsRegisterPair()) {
1903 return false;
1904 }
1905
1906 // For constants, we also check that the output is in one or two low registers,
1907 // and that the constants fit in an 8-bit unsigned integer, so that a 16-bit
1908 // MOV encoding can be used.
1909 if (src.IsConstant()) {
1910 if (!CanEncodeConstantAs8BitImmediate(src.GetConstant())) {
1911 return false;
1912 }
1913
1914 if (out.IsRegister()) {
1915 if (!ArmAssembler::IsLowRegister(out.AsRegister<Register>())) {
1916 return false;
1917 }
1918 } else {
1919 DCHECK(out.IsRegisterPair());
1920
1921 if (!ArmAssembler::IsLowRegister(out.AsRegisterPairHigh<Register>())) {
1922 return false;
1923 }
1924 }
1925 }
1926
1927 return true;
1928}
1929
Anton Kirilov74234da2017-01-13 14:42:47 +00001930#undef __
1931// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1932#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
1933
Donghui Bai426b49c2016-11-08 14:55:38 +08001934Label* CodeGeneratorARM::GetFinalLabel(HInstruction* instruction, Label* final_label) {
1935 DCHECK(!instruction->IsControlFlow() && !instruction->IsSuspendCheck());
Anton Kirilov6f644202017-02-27 18:29:45 +00001936 DCHECK(!instruction->IsInvoke() || !instruction->GetLocations()->CanCall());
Donghui Bai426b49c2016-11-08 14:55:38 +08001937
1938 const HBasicBlock* const block = instruction->GetBlock();
1939 const HLoopInformation* const info = block->GetLoopInformation();
1940 HInstruction* const next = instruction->GetNext();
1941
1942 // Avoid a branch to a branch.
1943 if (next->IsGoto() && (info == nullptr ||
1944 !info->IsBackEdge(*block) ||
1945 !info->HasSuspendCheck())) {
1946 final_label = GetLabelOf(next->AsGoto()->GetSuccessor());
1947 }
1948
1949 return final_label;
1950}
1951
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001952void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001953 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001954}
1955
1956void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001957 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001958}
1959
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001960size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1961 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
1962 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001963}
1964
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001965size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1966 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
1967 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001968}
1969
Nicolas Geoffray840e5462015-01-07 16:01:24 +00001970size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1971 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1972 return kArmWordSize;
1973}
1974
1975size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1976 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1977 return kArmWordSize;
1978}
1979
Calin Juravle34166012014-12-19 17:22:29 +00001980CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +00001981 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +01001982 const CompilerOptions& compiler_options,
1983 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001984 : CodeGenerator(graph,
1985 kNumberOfCoreRegisters,
1986 kNumberOfSRegisters,
1987 kNumberOfRegisterPairs,
1988 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1989 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +00001990 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1991 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01001992 compiler_options,
1993 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01001994 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001995 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001996 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001997 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +01001998 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +00001999 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00002000 uint32_literals_(std::less<uint32_t>(),
2001 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00002002 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2003 boot_image_string_patches_(StringReferenceValueComparator(),
2004 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2005 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01002006 boot_image_type_patches_(TypeReferenceValueComparator(),
2007 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2008 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +00002009 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01002010 baker_read_barrier_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray132d8362016-11-16 09:19:42 +00002011 jit_string_patches_(StringReferenceValueComparator(),
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00002012 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2013 jit_class_patches_(TypeReferenceValueComparator(),
2014 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -07002015 // Always save the LR register to mimic Quick.
2016 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +01002017}
2018
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002019void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
2020 // Ensure that we fix up branches and literal loads and emit the literal pool.
2021 __ FinalizeCode();
2022
2023 // Adjust native pc offsets in stack maps.
2024 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08002025 uint32_t old_position =
2026 stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kThumb2);
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002027 uint32_t new_position = __ GetAdjustedPosition(old_position);
2028 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
2029 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +01002030 // Adjust pc offsets for the disassembly information.
2031 if (disasm_info_ != nullptr) {
2032 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
2033 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
2034 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
2035 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
2036 it.second.start = __ GetAdjustedPosition(it.second.start);
2037 it.second.end = __ GetAdjustedPosition(it.second.end);
2038 }
2039 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
2040 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
2041 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
2042 }
2043 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002044
2045 CodeGenerator::Finalize(allocator);
2046}
2047
David Brazdil58282f42016-01-14 12:45:10 +00002048void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002049 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002050 blocked_core_registers_[SP] = true;
2051 blocked_core_registers_[LR] = true;
2052 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002053
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002054 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002055 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002056
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002057 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002058 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002059
David Brazdil58282f42016-01-14 12:45:10 +00002060 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +01002061 // Stubs do not save callee-save floating point registers. If the graph
2062 // is debuggable, we need to deal with these registers differently. For
2063 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002064 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
2065 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
2066 }
2067 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002068}
2069
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002070InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08002071 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002072 assembler_(codegen->GetAssembler()),
2073 codegen_(codegen) {}
2074
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002075void CodeGeneratorARM::ComputeSpillMask() {
2076 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
2077 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +00002078 // There is no easy instruction to restore just the PC on thumb2. We spill and
2079 // restore another arbitrary register.
2080 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002081 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
2082 // We use vpush and vpop for saving and restoring floating point registers, which take
2083 // a SRegister and the number of registers to save/restore after that SRegister. We
2084 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
2085 // but in the range.
2086 if (fpu_spill_mask_ != 0) {
2087 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
2088 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
2089 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
2090 fpu_spill_mask_ |= (1 << i);
2091 }
2092 }
2093}
2094
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002095static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002096 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002097}
2098
2099static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002100 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002101}
2102
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002103void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +00002104 bool skip_overflow_check =
2105 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002106 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00002107 __ Bind(&frame_entry_label_);
2108
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002109 if (HasEmptyFrame()) {
2110 return;
2111 }
2112
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002113 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002114 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
2115 __ LoadFromOffset(kLoadWord, IP, IP, 0);
2116 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002117 }
2118
Andreas Gampe501fd632015-09-10 16:11:06 -07002119 __ PushList(core_spill_mask_);
2120 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
2121 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002122 if (fpu_spill_mask_ != 0) {
2123 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2124 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002125 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +01002126 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002127 }
Mingyao Yang063fc772016-08-02 11:02:54 -07002128
2129 if (GetGraph()->HasShouldDeoptimizeFlag()) {
2130 // Initialize should_deoptimize flag to 0.
2131 __ mov(IP, ShifterOperand(0));
2132 __ StoreToOffset(kStoreWord, IP, SP, -kShouldDeoptimizeFlagSize);
2133 }
2134
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002135 int adjust = GetFrameSize() - FrameEntrySpillSize();
2136 __ AddConstant(SP, -adjust);
2137 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01002138
2139 // Save the current method if we need it. Note that we do not
2140 // do this in HCurrentMethod, as the instruction might have been removed
2141 // in the SSA graph.
2142 if (RequiresCurrentMethod()) {
2143 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
2144 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002145}
2146
2147void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002148 if (HasEmptyFrame()) {
2149 __ bx(LR);
2150 return;
2151 }
David Srbeckyc34dc932015-04-12 09:27:43 +01002152 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002153 int adjust = GetFrameSize() - FrameEntrySpillSize();
2154 __ AddConstant(SP, adjust);
2155 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002156 if (fpu_spill_mask_ != 0) {
2157 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2158 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
Andreas Gampe542451c2016-07-26 09:02:02 -07002159 __ cfi().AdjustCFAOffset(-static_cast<int>(kArmPointerSize) * POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002160 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002161 }
Andreas Gampe501fd632015-09-10 16:11:06 -07002162 // Pop LR into PC to return.
2163 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
2164 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
2165 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +01002166 __ cfi().RestoreState();
2167 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002168}
2169
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002170void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07002171 Label* label = GetLabelOf(block);
2172 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002173}
2174
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002175Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002176 switch (type) {
2177 case Primitive::kPrimBoolean:
2178 case Primitive::kPrimByte:
2179 case Primitive::kPrimChar:
2180 case Primitive::kPrimShort:
2181 case Primitive::kPrimInt:
2182 case Primitive::kPrimNot: {
2183 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002184 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002185 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002186 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002187 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002188 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002189 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002190 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002191
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002192 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002193 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002194 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002195 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002196 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002197 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002198 if (calling_convention.GetRegisterAt(index) == R1) {
2199 // Skip R1, and use R2_R3 instead.
2200 gp_index_++;
2201 index++;
2202 }
2203 }
2204 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
2205 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002206 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01002207
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002208 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002209 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002210 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002211 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
2212 }
2213 }
2214
2215 case Primitive::kPrimFloat: {
2216 uint32_t stack_index = stack_index_++;
2217 if (float_index_ % 2 == 0) {
2218 float_index_ = std::max(double_index_, float_index_);
2219 }
2220 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
2221 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
2222 } else {
2223 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
2224 }
2225 }
2226
2227 case Primitive::kPrimDouble: {
2228 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
2229 uint32_t stack_index = stack_index_;
2230 stack_index_ += 2;
2231 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
2232 uint32_t index = double_index_;
2233 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002234 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002235 calling_convention.GetFpuRegisterAt(index),
2236 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002237 DCHECK(ExpectedPairLayout(result));
2238 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002239 } else {
2240 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002241 }
2242 }
2243
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002244 case Primitive::kPrimVoid:
2245 LOG(FATAL) << "Unexpected parameter type " << type;
2246 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002247 }
Roland Levillain3b359c72015-11-17 19:35:12 +00002248 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002249}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002250
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002251Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002252 switch (type) {
2253 case Primitive::kPrimBoolean:
2254 case Primitive::kPrimByte:
2255 case Primitive::kPrimChar:
2256 case Primitive::kPrimShort:
2257 case Primitive::kPrimInt:
2258 case Primitive::kPrimNot: {
2259 return Location::RegisterLocation(R0);
2260 }
2261
2262 case Primitive::kPrimFloat: {
2263 return Location::FpuRegisterLocation(S0);
2264 }
2265
2266 case Primitive::kPrimLong: {
2267 return Location::RegisterPairLocation(R0, R1);
2268 }
2269
2270 case Primitive::kPrimDouble: {
2271 return Location::FpuRegisterPairLocation(S0, S1);
2272 }
2273
2274 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00002275 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002276 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002277
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002278 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002279}
2280
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002281Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
2282 return Location::RegisterLocation(kMethodRegisterArgument);
2283}
2284
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002285void CodeGeneratorARM::Move32(Location destination, Location source) {
2286 if (source.Equals(destination)) {
2287 return;
2288 }
2289 if (destination.IsRegister()) {
2290 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002291 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002292 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002293 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002294 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002295 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002296 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002297 } else if (destination.IsFpuRegister()) {
2298 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002299 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002300 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002301 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002302 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002303 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002304 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002305 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002306 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002307 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002308 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002309 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002310 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002311 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002312 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002313 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
2314 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002315 }
2316 }
2317}
2318
2319void CodeGeneratorARM::Move64(Location destination, Location source) {
2320 if (source.Equals(destination)) {
2321 return;
2322 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002323 if (destination.IsRegisterPair()) {
2324 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002325 EmitParallelMoves(
2326 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
2327 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002328 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002329 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002330 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
2331 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002332 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002333 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002334 } else if (source.IsFpuRegisterPair()) {
2335 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
2336 destination.AsRegisterPairHigh<Register>(),
2337 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002338 } else {
2339 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002340 DCHECK(ExpectedPairLayout(destination));
2341 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
2342 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002343 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002344 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002345 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002346 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2347 SP,
2348 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01002349 } else if (source.IsRegisterPair()) {
2350 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2351 source.AsRegisterPairLow<Register>(),
2352 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002353 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002354 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002355 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002356 } else {
2357 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002358 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002359 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002360 if (source.AsRegisterPairLow<Register>() == R1) {
2361 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002362 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
2363 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002364 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002365 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002366 SP, destination.GetStackIndex());
2367 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002368 } else if (source.IsFpuRegisterPair()) {
2369 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
2370 SP,
2371 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002372 } else {
2373 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002374 EmitParallelMoves(
2375 Location::StackSlot(source.GetStackIndex()),
2376 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002377 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002378 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002379 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
2380 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002381 }
2382 }
2383}
2384
Calin Juravle175dc732015-08-25 15:42:32 +01002385void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
2386 DCHECK(location.IsRegister());
2387 __ LoadImmediate(location.AsRegister<Register>(), value);
2388}
2389
Calin Juravlee460d1d2015-09-29 04:52:17 +01002390void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00002391 HParallelMove move(GetGraph()->GetArena());
2392 move.AddMove(src, dst, dst_type, nullptr);
2393 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002394}
2395
2396void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
2397 if (location.IsRegister()) {
2398 locations->AddTemp(location);
2399 } else if (location.IsRegisterPair()) {
2400 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
2401 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
2402 } else {
2403 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
2404 }
2405}
2406
Calin Juravle175dc732015-08-25 15:42:32 +01002407void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
2408 HInstruction* instruction,
2409 uint32_t dex_pc,
2410 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01002411 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002412 GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
Serban Constantinescuda8ffec2016-03-09 12:02:11 +00002413 if (EntrypointRequiresStackMap(entrypoint)) {
2414 RecordPcInfo(instruction, dex_pc, slow_path);
2415 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002416}
2417
Roland Levillaindec8f632016-07-22 17:10:06 +01002418void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
2419 HInstruction* instruction,
2420 SlowPathCode* slow_path) {
2421 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002422 GenerateInvokeRuntime(entry_point_offset);
2423}
2424
2425void CodeGeneratorARM::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01002426 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
2427 __ blx(LR);
2428}
2429
David Brazdilfc6a86a2015-06-26 10:33:45 +00002430void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002431 DCHECK(!successor->IsExitBlock());
2432
2433 HBasicBlock* block = got->GetBlock();
2434 HInstruction* previous = got->GetPrevious();
2435
2436 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00002437 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002438 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2439 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2440 return;
2441 }
2442
2443 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2444 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2445 }
2446 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002447 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002448 }
2449}
2450
David Brazdilfc6a86a2015-06-26 10:33:45 +00002451void LocationsBuilderARM::VisitGoto(HGoto* got) {
2452 got->SetLocations(nullptr);
2453}
2454
2455void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
2456 HandleGoto(got, got->GetSuccessor());
2457}
2458
2459void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2460 try_boundary->SetLocations(nullptr);
2461}
2462
2463void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2464 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2465 if (!successor->IsExitBlock()) {
2466 HandleGoto(try_boundary, successor);
2467 }
2468}
2469
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002470void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002471 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002472}
2473
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002474void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002475}
2476
Roland Levillain4fa13f62015-07-06 18:11:54 +01002477void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
2478 Label* true_label,
2479 Label* false_label) {
2480 LocationSummary* locations = cond->GetLocations();
2481 Location left = locations->InAt(0);
2482 Location right = locations->InAt(1);
2483 IfCondition if_cond = cond->GetCondition();
2484
2485 Register left_high = left.AsRegisterPairHigh<Register>();
2486 Register left_low = left.AsRegisterPairLow<Register>();
2487 IfCondition true_high_cond = if_cond;
2488 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07002489 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01002490
2491 // Set the conditions for the test, remembering that == needs to be
2492 // decided using the low words.
2493 switch (if_cond) {
2494 case kCondEQ:
2495 case kCondNE:
2496 // Nothing to do.
2497 break;
2498 case kCondLT:
2499 false_high_cond = kCondGT;
2500 break;
2501 case kCondLE:
2502 true_high_cond = kCondLT;
2503 break;
2504 case kCondGT:
2505 false_high_cond = kCondLT;
2506 break;
2507 case kCondGE:
2508 true_high_cond = kCondGT;
2509 break;
Aart Bike9f37602015-10-09 11:15:55 -07002510 case kCondB:
2511 false_high_cond = kCondA;
2512 break;
2513 case kCondBE:
2514 true_high_cond = kCondB;
2515 break;
2516 case kCondA:
2517 false_high_cond = kCondB;
2518 break;
2519 case kCondAE:
2520 true_high_cond = kCondA;
2521 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01002522 }
2523 if (right.IsConstant()) {
2524 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
2525 int32_t val_low = Low32Bits(value);
2526 int32_t val_high = High32Bits(value);
2527
Vladimir Markoac6ac102015-12-17 12:14:00 +00002528 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002529 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07002530 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002531 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07002532 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002533 } else {
Aart Bike9f37602015-10-09 11:15:55 -07002534 __ b(true_label, ARMCondition(true_high_cond));
2535 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002536 }
2537 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00002538 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002539 } else {
2540 Register right_high = right.AsRegisterPairHigh<Register>();
2541 Register right_low = right.AsRegisterPairLow<Register>();
2542
2543 __ cmp(left_high, ShifterOperand(right_high));
2544 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07002545 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002546 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07002547 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002548 } else {
Aart Bike9f37602015-10-09 11:15:55 -07002549 __ b(true_label, ARMCondition(true_high_cond));
2550 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002551 }
2552 // Must be equal high, so compare the lows.
2553 __ cmp(left_low, ShifterOperand(right_low));
2554 }
2555 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07002556 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01002557 __ b(true_label, final_condition);
2558}
2559
David Brazdil0debae72015-11-12 18:37:00 +00002560void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
2561 Label* true_target_in,
2562 Label* false_target_in) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002563 if (CanGenerateTest(condition, codegen_->GetAssembler())) {
2564 Label* non_fallthrough_target;
2565 bool invert;
2566
2567 if (true_target_in == nullptr) {
2568 DCHECK(false_target_in != nullptr);
2569 non_fallthrough_target = false_target_in;
2570 invert = true;
2571 } else {
2572 non_fallthrough_target = true_target_in;
2573 invert = false;
2574 }
2575
2576 const auto cond = GenerateTest(condition, invert, codegen_);
2577
2578 __ b(non_fallthrough_target, cond.first);
2579
2580 if (false_target_in != nullptr && false_target_in != non_fallthrough_target) {
2581 __ b(false_target_in);
2582 }
2583
2584 return;
2585 }
2586
David Brazdil0debae72015-11-12 18:37:00 +00002587 // Generated branching requires both targets to be explicit. If either of the
2588 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
2589 Label fallthrough_target;
2590 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
2591 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
2592
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002593 DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
2594 GenerateLongComparesAndJumps(condition, true_target, false_target);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002595
David Brazdil0debae72015-11-12 18:37:00 +00002596 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002597 __ b(false_target);
2598 }
David Brazdil0debae72015-11-12 18:37:00 +00002599
2600 if (fallthrough_target.IsLinked()) {
2601 __ Bind(&fallthrough_target);
2602 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01002603}
2604
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002605void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00002606 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002607 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00002608 Label* false_target) {
2609 HInstruction* cond = instruction->InputAt(condition_input_index);
2610
2611 if (true_target == nullptr && false_target == nullptr) {
2612 // Nothing to do. The code always falls through.
2613 return;
2614 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00002615 // Constant condition, statically compared against "true" (integer value 1).
2616 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00002617 if (true_target != nullptr) {
2618 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002619 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002620 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00002621 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00002622 if (false_target != nullptr) {
2623 __ b(false_target);
2624 }
2625 }
2626 return;
2627 }
2628
2629 // The following code generates these patterns:
2630 // (1) true_target == nullptr && false_target != nullptr
2631 // - opposite condition true => branch to false_target
2632 // (2) true_target != nullptr && false_target == nullptr
2633 // - condition true => branch to true_target
2634 // (3) true_target != nullptr && false_target != nullptr
2635 // - condition true => branch to true_target
2636 // - branch to false_target
2637 if (IsBooleanValueOrMaterializedCondition(cond)) {
2638 // Condition has been materialized, compare the output to 0.
2639 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
2640 DCHECK(cond_val.IsRegister());
2641 if (true_target == nullptr) {
2642 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
2643 } else {
2644 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002645 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002646 } else {
David Brazdil0debae72015-11-12 18:37:00 +00002647 // Condition has not been materialized. Use its inputs as the comparison and
2648 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04002649 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00002650
2651 // If this is a long or FP comparison that has been folded into
2652 // the HCondition, generate the comparison directly.
2653 Primitive::Type type = condition->InputAt(0)->GetType();
2654 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
2655 GenerateCompareTestAndBranch(condition, true_target, false_target);
2656 return;
2657 }
2658
Donghui Bai426b49c2016-11-08 14:55:38 +08002659 Label* non_fallthrough_target;
2660 Condition arm_cond;
David Brazdil0debae72015-11-12 18:37:00 +00002661 LocationSummary* locations = cond->GetLocations();
2662 DCHECK(locations->InAt(0).IsRegister());
2663 Register left = locations->InAt(0).AsRegister<Register>();
2664 Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08002665
David Brazdil0debae72015-11-12 18:37:00 +00002666 if (true_target == nullptr) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002667 arm_cond = ARMCondition(condition->GetOppositeCondition());
2668 non_fallthrough_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00002669 } else {
Donghui Bai426b49c2016-11-08 14:55:38 +08002670 arm_cond = ARMCondition(condition->GetCondition());
2671 non_fallthrough_target = true_target;
2672 }
2673
2674 if (right.IsConstant() && (arm_cond == NE || arm_cond == EQ) &&
2675 CodeGenerator::GetInt32ValueOf(right.GetConstant()) == 0) {
2676 if (arm_cond == EQ) {
2677 __ CompareAndBranchIfZero(left, non_fallthrough_target);
2678 } else {
2679 DCHECK_EQ(arm_cond, NE);
2680 __ CompareAndBranchIfNonZero(left, non_fallthrough_target);
2681 }
2682 } else {
2683 if (right.IsRegister()) {
2684 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
2685 } else {
2686 DCHECK(right.IsConstant());
2687 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
2688 }
2689
2690 __ b(non_fallthrough_target, arm_cond);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002691 }
Dave Allison20dfc792014-06-16 20:44:29 -07002692 }
David Brazdil0debae72015-11-12 18:37:00 +00002693
2694 // If neither branch falls through (case 3), the conditional branch to `true_target`
2695 // was already emitted (case 2) and we need to emit a jump to `false_target`.
2696 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002697 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002698 }
2699}
2700
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002701void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00002702 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
2703 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002704 locations->SetInAt(0, Location::RequiresRegister());
2705 }
2706}
2707
2708void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00002709 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
2710 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
2711 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
2712 nullptr : codegen_->GetLabelOf(true_successor);
2713 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
2714 nullptr : codegen_->GetLabelOf(false_successor);
2715 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002716}
2717
2718void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
2719 LocationSummary* locations = new (GetGraph()->GetArena())
2720 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01002721 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
David Brazdil0debae72015-11-12 18:37:00 +00002722 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002723 locations->SetInAt(0, Location::RequiresRegister());
2724 }
2725}
2726
2727void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01002728 SlowPathCodeARM* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00002729 GenerateTestAndBranch(deoptimize,
2730 /* condition_input_index */ 0,
2731 slow_path->GetEntryLabel(),
2732 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002733}
Dave Allison20dfc792014-06-16 20:44:29 -07002734
Mingyao Yang063fc772016-08-02 11:02:54 -07002735void LocationsBuilderARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2736 LocationSummary* locations = new (GetGraph()->GetArena())
2737 LocationSummary(flag, LocationSummary::kNoCall);
2738 locations->SetOut(Location::RequiresRegister());
2739}
2740
2741void InstructionCodeGeneratorARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2742 __ LoadFromOffset(kLoadWord,
2743 flag->GetLocations()->Out().AsRegister<Register>(),
2744 SP,
2745 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
2746}
2747
David Brazdil74eb1b22015-12-14 11:44:01 +00002748void LocationsBuilderARM::VisitSelect(HSelect* select) {
2749 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
Donghui Bai426b49c2016-11-08 14:55:38 +08002750 const bool is_floating_point = Primitive::IsFloatingPointType(select->GetType());
2751
2752 if (is_floating_point) {
David Brazdil74eb1b22015-12-14 11:44:01 +00002753 locations->SetInAt(0, Location::RequiresFpuRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08002754 locations->SetInAt(1, Location::FpuRegisterOrConstant(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00002755 } else {
2756 locations->SetInAt(0, Location::RequiresRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08002757 locations->SetInAt(1, Arm8BitEncodableConstantOrRegister(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00002758 }
Donghui Bai426b49c2016-11-08 14:55:38 +08002759
David Brazdil74eb1b22015-12-14 11:44:01 +00002760 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002761 locations->SetInAt(2, Location::RegisterOrConstant(select->GetCondition()));
2762 // The code generator handles overlap with the values, but not with the condition.
2763 locations->SetOut(Location::SameAsFirstInput());
2764 } else if (is_floating_point) {
2765 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2766 } else {
2767 if (!locations->InAt(1).IsConstant()) {
2768 locations->SetInAt(0, Arm8BitEncodableConstantOrRegister(select->GetFalseValue()));
2769 }
2770
2771 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
David Brazdil74eb1b22015-12-14 11:44:01 +00002772 }
David Brazdil74eb1b22015-12-14 11:44:01 +00002773}
2774
2775void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002776 HInstruction* const condition = select->GetCondition();
2777 const LocationSummary* const locations = select->GetLocations();
2778 const Primitive::Type type = select->GetType();
2779 const Location first = locations->InAt(0);
2780 const Location out = locations->Out();
2781 const Location second = locations->InAt(1);
2782 Location src;
2783
2784 if (condition->IsIntConstant()) {
2785 if (condition->AsIntConstant()->IsFalse()) {
2786 src = first;
2787 } else {
2788 src = second;
2789 }
2790
2791 codegen_->MoveLocation(out, src, type);
2792 return;
2793 }
2794
2795 if (!Primitive::IsFloatingPointType(type) &&
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002796 (IsBooleanValueOrMaterializedCondition(condition) ||
2797 CanGenerateTest(condition->AsCondition(), codegen_->GetAssembler()))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002798 bool invert = false;
2799
2800 if (out.Equals(second)) {
2801 src = first;
2802 invert = true;
2803 } else if (out.Equals(first)) {
2804 src = second;
2805 } else if (second.IsConstant()) {
2806 DCHECK(CanEncodeConstantAs8BitImmediate(second.GetConstant()));
2807 src = second;
2808 } else if (first.IsConstant()) {
2809 DCHECK(CanEncodeConstantAs8BitImmediate(first.GetConstant()));
2810 src = first;
2811 invert = true;
2812 } else {
2813 src = second;
2814 }
2815
2816 if (CanGenerateConditionalMove(out, src)) {
2817 if (!out.Equals(first) && !out.Equals(second)) {
2818 codegen_->MoveLocation(out, src.Equals(first) ? second : first, type);
2819 }
2820
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002821 std::pair<Condition, Condition> cond;
2822
2823 if (IsBooleanValueOrMaterializedCondition(condition)) {
2824 __ CmpConstant(locations->InAt(2).AsRegister<Register>(), 0);
2825 cond = invert ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
2826 } else {
2827 cond = GenerateTest(condition->AsCondition(), invert, codegen_);
2828 }
Donghui Bai426b49c2016-11-08 14:55:38 +08002829
2830 if (out.IsRegister()) {
2831 ShifterOperand operand;
2832
2833 if (src.IsConstant()) {
2834 operand = ShifterOperand(CodeGenerator::GetInt32ValueOf(src.GetConstant()));
2835 } else {
2836 DCHECK(src.IsRegister());
2837 operand = ShifterOperand(src.AsRegister<Register>());
2838 }
2839
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002840 __ it(cond.first);
2841 __ mov(out.AsRegister<Register>(), operand, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08002842 } else {
2843 DCHECK(out.IsRegisterPair());
2844
2845 ShifterOperand operand_high;
2846 ShifterOperand operand_low;
2847
2848 if (src.IsConstant()) {
2849 const int64_t value = src.GetConstant()->AsLongConstant()->GetValue();
2850
2851 operand_high = ShifterOperand(High32Bits(value));
2852 operand_low = ShifterOperand(Low32Bits(value));
2853 } else {
2854 DCHECK(src.IsRegisterPair());
2855 operand_high = ShifterOperand(src.AsRegisterPairHigh<Register>());
2856 operand_low = ShifterOperand(src.AsRegisterPairLow<Register>());
2857 }
2858
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002859 __ it(cond.first);
2860 __ mov(out.AsRegisterPairLow<Register>(), operand_low, cond.first);
2861 __ it(cond.first);
2862 __ mov(out.AsRegisterPairHigh<Register>(), operand_high, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08002863 }
2864
2865 return;
2866 }
2867 }
2868
2869 Label* false_target = nullptr;
2870 Label* true_target = nullptr;
2871 Label select_end;
2872 Label* target = codegen_->GetFinalLabel(select, &select_end);
2873
2874 if (out.Equals(second)) {
2875 true_target = target;
2876 src = first;
2877 } else {
2878 false_target = target;
2879 src = second;
2880
2881 if (!out.Equals(first)) {
2882 codegen_->MoveLocation(out, first, type);
2883 }
2884 }
2885
2886 GenerateTestAndBranch(select, 2, true_target, false_target);
2887 codegen_->MoveLocation(out, src, type);
2888
2889 if (select_end.IsLinked()) {
2890 __ Bind(&select_end);
2891 }
David Brazdil74eb1b22015-12-14 11:44:01 +00002892}
2893
David Srbecky0cf44932015-12-09 14:09:59 +00002894void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
2895 new (GetGraph()->GetArena()) LocationSummary(info);
2896}
2897
David Srbeckyd28f4a02016-03-14 17:14:24 +00002898void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
2899 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00002900}
2901
2902void CodeGeneratorARM::GenerateNop() {
2903 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00002904}
2905
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002906void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002907 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01002908 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002909 // Handle the long/FP comparisons made in instruction simplification.
2910 switch (cond->InputAt(0)->GetType()) {
2911 case Primitive::kPrimLong:
2912 locations->SetInAt(0, Location::RequiresRegister());
2913 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002914 if (!cond->IsEmittedAtUseSite()) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002915 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002916 }
2917 break;
2918
2919 case Primitive::kPrimFloat:
2920 case Primitive::kPrimDouble:
2921 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01002922 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002923 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002924 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2925 }
2926 break;
2927
2928 default:
2929 locations->SetInAt(0, Location::RequiresRegister());
2930 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002931 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002932 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2933 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002934 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002935}
2936
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002937void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002938 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002939 return;
Dave Allison20dfc792014-06-16 20:44:29 -07002940 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01002941
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002942 const Register out = cond->GetLocations()->Out().AsRegister<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01002943
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002944 if (ArmAssembler::IsLowRegister(out) && CanGenerateTest(cond, codegen_->GetAssembler())) {
2945 const auto condition = GenerateTest(cond, false, codegen_);
2946
2947 __ it(condition.first);
2948 __ mov(out, ShifterOperand(1), condition.first);
2949 __ it(condition.second);
2950 __ mov(out, ShifterOperand(0), condition.second);
2951 return;
Roland Levillain4fa13f62015-07-06 18:11:54 +01002952 }
2953
2954 // Convert the jumps into the result.
2955 Label done_label;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002956 Label* const final_label = codegen_->GetFinalLabel(cond, &done_label);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002957
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002958 if (cond->InputAt(0)->GetType() == Primitive::kPrimLong) {
2959 Label true_label, false_label;
Roland Levillain4fa13f62015-07-06 18:11:54 +01002960
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002961 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
2962
2963 // False case: result = 0.
2964 __ Bind(&false_label);
2965 __ LoadImmediate(out, 0);
2966 __ b(final_label);
2967
2968 // True case: result = 1.
2969 __ Bind(&true_label);
2970 __ LoadImmediate(out, 1);
2971 } else {
2972 DCHECK(CanGenerateTest(cond, codegen_->GetAssembler()));
2973
2974 const auto condition = GenerateTest(cond, false, codegen_);
2975
2976 __ mov(out, ShifterOperand(0), AL, kCcKeep);
2977 __ b(final_label, condition.second);
2978 __ LoadImmediate(out, 1);
2979 }
Anton Kirilov6f644202017-02-27 18:29:45 +00002980
2981 if (done_label.IsLinked()) {
2982 __ Bind(&done_label);
2983 }
Dave Allison20dfc792014-06-16 20:44:29 -07002984}
2985
2986void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002987 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002988}
2989
2990void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002991 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002992}
2993
2994void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002995 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002996}
2997
2998void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002999 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003000}
3001
3002void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003003 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003004}
3005
3006void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003007 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003008}
3009
3010void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003011 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003012}
3013
3014void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003015 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003016}
3017
3018void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003019 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003020}
3021
3022void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003023 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003024}
3025
3026void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003027 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003028}
3029
3030void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003031 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003032}
3033
Aart Bike9f37602015-10-09 11:15:55 -07003034void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003035 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003036}
3037
3038void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003039 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003040}
3041
3042void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003043 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003044}
3045
3046void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003047 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003048}
3049
3050void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003051 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003052}
3053
3054void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003055 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003056}
3057
3058void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003059 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003060}
3061
3062void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003063 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003064}
3065
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003066void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003067 LocationSummary* locations =
3068 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003069 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003070}
3071
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003072void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01003073 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003074}
3075
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003076void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
3077 LocationSummary* locations =
3078 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3079 locations->SetOut(Location::ConstantLocation(constant));
3080}
3081
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003082void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003083 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003084}
3085
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003086void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003087 LocationSummary* locations =
3088 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003089 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003090}
3091
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003092void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003093 // Will be generated at use site.
3094}
3095
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003096void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
3097 LocationSummary* locations =
3098 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3099 locations->SetOut(Location::ConstantLocation(constant));
3100}
3101
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003102void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003103 // Will be generated at use site.
3104}
3105
3106void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
3107 LocationSummary* locations =
3108 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3109 locations->SetOut(Location::ConstantLocation(constant));
3110}
3111
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003112void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003113 // Will be generated at use site.
3114}
3115
Igor Murashkind01745e2017-04-05 16:40:31 -07003116void LocationsBuilderARM::VisitConstructorFence(HConstructorFence* constructor_fence) {
3117 constructor_fence->SetLocations(nullptr);
3118}
3119
3120void InstructionCodeGeneratorARM::VisitConstructorFence(
3121 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
3122 codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
3123}
3124
Calin Juravle27df7582015-04-17 19:12:31 +01003125void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
3126 memory_barrier->SetLocations(nullptr);
3127}
3128
3129void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00003130 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01003131}
3132
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003133void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003134 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003135}
3136
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003137void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003138 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003139}
3140
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003141void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003142 LocationSummary* locations =
3143 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003144 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003145}
3146
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003147void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003148 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003149}
3150
Calin Juravle175dc732015-08-25 15:42:32 +01003151void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3152 // The trampoline uses the same calling convention as dex calling conventions,
3153 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
3154 // the method_idx.
3155 HandleInvoke(invoke);
3156}
3157
3158void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3159 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
3160}
3161
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003162void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003163 // Explicit clinit checks triggered by static invokes must have been pruned by
3164 // art::PrepareForRegisterAllocation.
3165 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003166
Vladimir Marko68c981f2016-08-26 13:13:33 +01003167 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003168 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00003169 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
3170 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
3171 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003172 return;
3173 }
3174
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003175 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00003176
3177 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
3178 if (invoke->HasPcRelativeDexCache()) {
3179 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
3180 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003181}
3182
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003183static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
3184 if (invoke->GetLocations()->Intrinsified()) {
3185 IntrinsicCodeGeneratorARM intrinsic(codegen);
3186 intrinsic.Dispatch(invoke);
3187 return true;
3188 }
3189 return false;
3190}
3191
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003192void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003193 // Explicit clinit checks triggered by static invokes must have been pruned by
3194 // art::PrepareForRegisterAllocation.
3195 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003196
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003197 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3198 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00003199 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003200
Nicolas Geoffray38207af2015-06-01 15:46:22 +01003201 LocationSummary* locations = invoke->GetLocations();
3202 codegen_->GenerateStaticOrDirectCall(
3203 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00003204 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003205}
3206
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003207void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01003208 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01003209 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003210}
3211
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003212void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Vladimir Marko68c981f2016-08-26 13:13:33 +01003213 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003214 if (intrinsic.TryDispatch(invoke)) {
3215 return;
3216 }
3217
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003218 HandleInvoke(invoke);
3219}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003220
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003221void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003222 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3223 return;
3224 }
3225
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003226 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003227 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003228 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003229}
3230
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003231void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3232 HandleInvoke(invoke);
3233 // Add the hidden argument.
3234 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
3235}
3236
3237void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3238 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00003239 LocationSummary* locations = invoke->GetLocations();
3240 Register temp = locations->GetTemp(0).AsRegister<Register>();
3241 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003242 Location receiver = locations->InAt(0);
3243 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3244
Roland Levillain3b359c72015-11-17 19:35:12 +00003245 // Set the hidden argument. This is safe to do this here, as R12
3246 // won't be modified thereafter, before the `blx` (call) instruction.
3247 DCHECK_EQ(R12, hidden_reg);
3248 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003249
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003250 if (receiver.IsStackSlot()) {
3251 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00003252 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003253 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
3254 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00003255 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00003256 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003257 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003258 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00003259 // Instead of simply (possibly) unpoisoning `temp` here, we should
3260 // emit a read barrier for the previous class reference load.
3261 // However this is not required in practice, as this is an
3262 // intermediate/temporary reference and because the current
3263 // concurrent copying collector keeps the from-space memory
3264 // intact/accessible until the end of the marking phase (the
3265 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01003266 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003267 __ LoadFromOffset(kLoadWord, temp, temp,
3268 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
3269 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00003270 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003271 // temp = temp->GetImtEntryAt(method_offset);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003272 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00003273 uint32_t entry_point =
Andreas Gampe542451c2016-07-26 09:02:02 -07003274 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003275 // LR = temp->GetEntryPoint();
3276 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
3277 // LR();
3278 __ blx(LR);
3279 DCHECK(!codegen_->IsLeafMethod());
3280 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3281}
3282
Orion Hodsonac141392017-01-13 11:53:47 +00003283void LocationsBuilderARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3284 HandleInvoke(invoke);
3285}
3286
3287void InstructionCodeGeneratorARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3288 codegen_->GenerateInvokePolymorphicCall(invoke);
3289}
3290
Roland Levillain88cb1752014-10-20 16:36:47 +01003291void LocationsBuilderARM::VisitNeg(HNeg* neg) {
3292 LocationSummary* locations =
3293 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
3294 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003295 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01003296 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003297 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3298 break;
3299 }
3300 case Primitive::kPrimLong: {
3301 locations->SetInAt(0, Location::RequiresRegister());
3302 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003303 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003304 }
Roland Levillain88cb1752014-10-20 16:36:47 +01003305
Roland Levillain88cb1752014-10-20 16:36:47 +01003306 case Primitive::kPrimFloat:
3307 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003308 locations->SetInAt(0, Location::RequiresFpuRegister());
3309 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003310 break;
3311
3312 default:
3313 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3314 }
3315}
3316
3317void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
3318 LocationSummary* locations = neg->GetLocations();
3319 Location out = locations->Out();
3320 Location in = locations->InAt(0);
3321 switch (neg->GetResultType()) {
3322 case Primitive::kPrimInt:
3323 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003324 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01003325 break;
3326
3327 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003328 DCHECK(in.IsRegisterPair());
3329 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
3330 __ rsbs(out.AsRegisterPairLow<Register>(),
3331 in.AsRegisterPairLow<Register>(),
3332 ShifterOperand(0));
3333 // We cannot emit an RSC (Reverse Subtract with Carry)
3334 // instruction here, as it does not exist in the Thumb-2
3335 // instruction set. We use the following approach
3336 // using SBC and SUB instead.
3337 //
3338 // out.hi = -C
3339 __ sbc(out.AsRegisterPairHigh<Register>(),
3340 out.AsRegisterPairHigh<Register>(),
3341 ShifterOperand(out.AsRegisterPairHigh<Register>()));
3342 // out.hi = out.hi - in.hi
3343 __ sub(out.AsRegisterPairHigh<Register>(),
3344 out.AsRegisterPairHigh<Register>(),
3345 ShifterOperand(in.AsRegisterPairHigh<Register>()));
3346 break;
3347
Roland Levillain88cb1752014-10-20 16:36:47 +01003348 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003349 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003350 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00003351 break;
3352
Roland Levillain88cb1752014-10-20 16:36:47 +01003353 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003354 DCHECK(in.IsFpuRegisterPair());
3355 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3356 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01003357 break;
3358
3359 default:
3360 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3361 }
3362}
3363
Roland Levillaindff1f282014-11-05 14:15:05 +00003364void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00003365 Primitive::Type result_type = conversion->GetResultType();
3366 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003367 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00003368
Roland Levillain5b3ee562015-04-14 16:02:41 +01003369 // The float-to-long, double-to-long and long-to-float type conversions
3370 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00003371 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01003372 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
3373 && result_type == Primitive::kPrimLong)
3374 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003375 ? LocationSummary::kCallOnMainOnly
Roland Levillain624279f2014-12-04 11:54:28 +00003376 : LocationSummary::kNoCall;
3377 LocationSummary* locations =
3378 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
3379
David Brazdilb2bd1c52015-03-25 11:17:37 +00003380 // The Java language does not allow treating boolean as an integral type but
3381 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00003382
Roland Levillaindff1f282014-11-05 14:15:05 +00003383 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003384 case Primitive::kPrimByte:
3385 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003386 case Primitive::kPrimLong:
3387 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003388 case Primitive::kPrimBoolean:
3389 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003390 case Primitive::kPrimShort:
3391 case Primitive::kPrimInt:
3392 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003393 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003394 locations->SetInAt(0, Location::RequiresRegister());
3395 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3396 break;
3397
3398 default:
3399 LOG(FATAL) << "Unexpected type conversion from " << input_type
3400 << " to " << result_type;
3401 }
3402 break;
3403
Roland Levillain01a8d712014-11-14 16:27:39 +00003404 case Primitive::kPrimShort:
3405 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003406 case Primitive::kPrimLong:
3407 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003408 case Primitive::kPrimBoolean:
3409 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00003410 case Primitive::kPrimByte:
3411 case Primitive::kPrimInt:
3412 case Primitive::kPrimChar:
3413 // Processing a Dex `int-to-short' instruction.
3414 locations->SetInAt(0, Location::RequiresRegister());
3415 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3416 break;
3417
3418 default:
3419 LOG(FATAL) << "Unexpected type conversion from " << input_type
3420 << " to " << result_type;
3421 }
3422 break;
3423
Roland Levillain946e1432014-11-11 17:35:19 +00003424 case Primitive::kPrimInt:
3425 switch (input_type) {
3426 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00003427 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00003428 locations->SetInAt(0, Location::Any());
3429 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3430 break;
3431
3432 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00003433 // Processing a Dex `float-to-int' instruction.
3434 locations->SetInAt(0, Location::RequiresFpuRegister());
3435 locations->SetOut(Location::RequiresRegister());
3436 locations->AddTemp(Location::RequiresFpuRegister());
3437 break;
3438
Roland Levillain946e1432014-11-11 17:35:19 +00003439 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003440 // Processing a Dex `double-to-int' instruction.
3441 locations->SetInAt(0, Location::RequiresFpuRegister());
3442 locations->SetOut(Location::RequiresRegister());
3443 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00003444 break;
3445
3446 default:
3447 LOG(FATAL) << "Unexpected type conversion from " << input_type
3448 << " to " << result_type;
3449 }
3450 break;
3451
Roland Levillaindff1f282014-11-05 14:15:05 +00003452 case Primitive::kPrimLong:
3453 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003454 case Primitive::kPrimBoolean:
3455 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00003456 case Primitive::kPrimByte:
3457 case Primitive::kPrimShort:
3458 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00003459 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003460 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00003461 locations->SetInAt(0, Location::RequiresRegister());
3462 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3463 break;
3464
Roland Levillain624279f2014-12-04 11:54:28 +00003465 case Primitive::kPrimFloat: {
3466 // Processing a Dex `float-to-long' instruction.
3467 InvokeRuntimeCallingConvention calling_convention;
3468 locations->SetInAt(0, Location::FpuRegisterLocation(
3469 calling_convention.GetFpuRegisterAt(0)));
3470 locations->SetOut(Location::RegisterPairLocation(R0, R1));
3471 break;
3472 }
3473
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003474 case Primitive::kPrimDouble: {
3475 // Processing a Dex `double-to-long' instruction.
3476 InvokeRuntimeCallingConvention calling_convention;
3477 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3478 calling_convention.GetFpuRegisterAt(0),
3479 calling_convention.GetFpuRegisterAt(1)));
3480 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00003481 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003482 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003483
3484 default:
3485 LOG(FATAL) << "Unexpected type conversion from " << input_type
3486 << " to " << result_type;
3487 }
3488 break;
3489
Roland Levillain981e4542014-11-14 11:47:14 +00003490 case Primitive::kPrimChar:
3491 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003492 case Primitive::kPrimLong:
3493 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003494 case Primitive::kPrimBoolean:
3495 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00003496 case Primitive::kPrimByte:
3497 case Primitive::kPrimShort:
3498 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00003499 // Processing a Dex `int-to-char' instruction.
3500 locations->SetInAt(0, Location::RequiresRegister());
3501 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3502 break;
3503
3504 default:
3505 LOG(FATAL) << "Unexpected type conversion from " << input_type
3506 << " to " << result_type;
3507 }
3508 break;
3509
Roland Levillaindff1f282014-11-05 14:15:05 +00003510 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00003511 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003512 case Primitive::kPrimBoolean:
3513 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003514 case Primitive::kPrimByte:
3515 case Primitive::kPrimShort:
3516 case Primitive::kPrimInt:
3517 case Primitive::kPrimChar:
3518 // Processing a Dex `int-to-float' instruction.
3519 locations->SetInAt(0, Location::RequiresRegister());
3520 locations->SetOut(Location::RequiresFpuRegister());
3521 break;
3522
Roland Levillain5b3ee562015-04-14 16:02:41 +01003523 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00003524 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01003525 InvokeRuntimeCallingConvention calling_convention;
3526 locations->SetInAt(0, Location::RegisterPairLocation(
3527 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3528 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00003529 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01003530 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00003531
Roland Levillaincff13742014-11-17 14:32:17 +00003532 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003533 // Processing a Dex `double-to-float' instruction.
3534 locations->SetInAt(0, Location::RequiresFpuRegister());
3535 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003536 break;
3537
3538 default:
3539 LOG(FATAL) << "Unexpected type conversion from " << input_type
3540 << " to " << result_type;
3541 };
3542 break;
3543
Roland Levillaindff1f282014-11-05 14:15:05 +00003544 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00003545 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003546 case Primitive::kPrimBoolean:
3547 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003548 case Primitive::kPrimByte:
3549 case Primitive::kPrimShort:
3550 case Primitive::kPrimInt:
3551 case Primitive::kPrimChar:
3552 // Processing a Dex `int-to-double' instruction.
3553 locations->SetInAt(0, Location::RequiresRegister());
3554 locations->SetOut(Location::RequiresFpuRegister());
3555 break;
3556
3557 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00003558 // Processing a Dex `long-to-double' instruction.
3559 locations->SetInAt(0, Location::RequiresRegister());
3560 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01003561 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00003562 locations->AddTemp(Location::RequiresFpuRegister());
3563 break;
3564
Roland Levillaincff13742014-11-17 14:32:17 +00003565 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003566 // Processing a Dex `float-to-double' instruction.
3567 locations->SetInAt(0, Location::RequiresFpuRegister());
3568 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003569 break;
3570
3571 default:
3572 LOG(FATAL) << "Unexpected type conversion from " << input_type
3573 << " to " << result_type;
3574 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003575 break;
3576
3577 default:
3578 LOG(FATAL) << "Unexpected type conversion from " << input_type
3579 << " to " << result_type;
3580 }
3581}
3582
3583void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
3584 LocationSummary* locations = conversion->GetLocations();
3585 Location out = locations->Out();
3586 Location in = locations->InAt(0);
3587 Primitive::Type result_type = conversion->GetResultType();
3588 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003589 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00003590 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003591 case Primitive::kPrimByte:
3592 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003593 case Primitive::kPrimLong:
3594 // Type conversion from long to byte is a result of code transformations.
3595 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
3596 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003597 case Primitive::kPrimBoolean:
3598 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003599 case Primitive::kPrimShort:
3600 case Primitive::kPrimInt:
3601 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003602 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003603 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00003604 break;
3605
3606 default:
3607 LOG(FATAL) << "Unexpected type conversion from " << input_type
3608 << " to " << result_type;
3609 }
3610 break;
3611
Roland Levillain01a8d712014-11-14 16:27:39 +00003612 case Primitive::kPrimShort:
3613 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003614 case Primitive::kPrimLong:
3615 // Type conversion from long to short is a result of code transformations.
3616 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
3617 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003618 case Primitive::kPrimBoolean:
3619 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00003620 case Primitive::kPrimByte:
3621 case Primitive::kPrimInt:
3622 case Primitive::kPrimChar:
3623 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003624 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00003625 break;
3626
3627 default:
3628 LOG(FATAL) << "Unexpected type conversion from " << input_type
3629 << " to " << result_type;
3630 }
3631 break;
3632
Roland Levillain946e1432014-11-11 17:35:19 +00003633 case Primitive::kPrimInt:
3634 switch (input_type) {
3635 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00003636 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00003637 DCHECK(out.IsRegister());
3638 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003639 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00003640 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003641 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00003642 } else {
3643 DCHECK(in.IsConstant());
3644 DCHECK(in.GetConstant()->IsLongConstant());
3645 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003646 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00003647 }
3648 break;
3649
Roland Levillain3f8f9362014-12-02 17:45:01 +00003650 case Primitive::kPrimFloat: {
3651 // Processing a Dex `float-to-int' instruction.
3652 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01003653 __ vcvtis(temp, in.AsFpuRegister<SRegister>());
Roland Levillain3f8f9362014-12-02 17:45:01 +00003654 __ vmovrs(out.AsRegister<Register>(), temp);
3655 break;
3656 }
3657
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003658 case Primitive::kPrimDouble: {
3659 // Processing a Dex `double-to-int' instruction.
3660 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01003661 __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003662 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00003663 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003664 }
Roland Levillain946e1432014-11-11 17:35:19 +00003665
3666 default:
3667 LOG(FATAL) << "Unexpected type conversion from " << input_type
3668 << " to " << result_type;
3669 }
3670 break;
3671
Roland Levillaindff1f282014-11-05 14:15:05 +00003672 case Primitive::kPrimLong:
3673 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003674 case Primitive::kPrimBoolean:
3675 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00003676 case Primitive::kPrimByte:
3677 case Primitive::kPrimShort:
3678 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00003679 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003680 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00003681 DCHECK(out.IsRegisterPair());
3682 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003683 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00003684 // Sign extension.
3685 __ Asr(out.AsRegisterPairHigh<Register>(),
3686 out.AsRegisterPairLow<Register>(),
3687 31);
3688 break;
3689
3690 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00003691 // Processing a Dex `float-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003692 codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003693 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00003694 break;
3695
Roland Levillaindff1f282014-11-05 14:15:05 +00003696 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003697 // Processing a Dex `double-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003698 codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003699 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00003700 break;
3701
3702 default:
3703 LOG(FATAL) << "Unexpected type conversion from " << input_type
3704 << " to " << result_type;
3705 }
3706 break;
3707
Roland Levillain981e4542014-11-14 11:47:14 +00003708 case Primitive::kPrimChar:
3709 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003710 case Primitive::kPrimLong:
3711 // Type conversion from long to char is a result of code transformations.
3712 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
3713 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003714 case Primitive::kPrimBoolean:
3715 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00003716 case Primitive::kPrimByte:
3717 case Primitive::kPrimShort:
3718 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00003719 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003720 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00003721 break;
3722
3723 default:
3724 LOG(FATAL) << "Unexpected type conversion from " << input_type
3725 << " to " << result_type;
3726 }
3727 break;
3728
Roland Levillaindff1f282014-11-05 14:15:05 +00003729 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00003730 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003731 case Primitive::kPrimBoolean:
3732 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003733 case Primitive::kPrimByte:
3734 case Primitive::kPrimShort:
3735 case Primitive::kPrimInt:
3736 case Primitive::kPrimChar: {
3737 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003738 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
3739 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00003740 break;
3741 }
3742
Roland Levillain5b3ee562015-04-14 16:02:41 +01003743 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00003744 // Processing a Dex `long-to-float' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003745 codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003746 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00003747 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00003748
Roland Levillaincff13742014-11-17 14:32:17 +00003749 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003750 // Processing a Dex `double-to-float' instruction.
3751 __ vcvtsd(out.AsFpuRegister<SRegister>(),
3752 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00003753 break;
3754
3755 default:
3756 LOG(FATAL) << "Unexpected type conversion from " << input_type
3757 << " to " << result_type;
3758 };
3759 break;
3760
Roland Levillaindff1f282014-11-05 14:15:05 +00003761 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00003762 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003763 case Primitive::kPrimBoolean:
3764 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003765 case Primitive::kPrimByte:
3766 case Primitive::kPrimShort:
3767 case Primitive::kPrimInt:
3768 case Primitive::kPrimChar: {
3769 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003770 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00003771 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3772 out.AsFpuRegisterPairLow<SRegister>());
3773 break;
3774 }
3775
Roland Levillain647b9ed2014-11-27 12:06:00 +00003776 case Primitive::kPrimLong: {
3777 // Processing a Dex `long-to-double' instruction.
3778 Register low = in.AsRegisterPairLow<Register>();
3779 Register high = in.AsRegisterPairHigh<Register>();
3780 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
3781 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01003782 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00003783 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01003784 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
3785 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00003786
Roland Levillain682393c2015-04-14 15:57:52 +01003787 // temp_d = int-to-double(high)
3788 __ vmovsr(temp_s, high);
3789 __ vcvtdi(temp_d, temp_s);
3790 // constant_d = k2Pow32EncodingForDouble
3791 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
3792 // out_d = unsigned-to-double(low)
3793 __ vmovsr(out_s, low);
3794 __ vcvtdu(out_d, out_s);
3795 // out_d += temp_d * constant_d
3796 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00003797 break;
3798 }
3799
Roland Levillaincff13742014-11-17 14:32:17 +00003800 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003801 // Processing a Dex `float-to-double' instruction.
3802 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3803 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00003804 break;
3805
3806 default:
3807 LOG(FATAL) << "Unexpected type conversion from " << input_type
3808 << " to " << result_type;
3809 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003810 break;
3811
3812 default:
3813 LOG(FATAL) << "Unexpected type conversion from " << input_type
3814 << " to " << result_type;
3815 }
3816}
3817
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003818void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003819 LocationSummary* locations =
3820 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003821 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003822 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003823 locations->SetInAt(0, Location::RequiresRegister());
3824 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003825 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3826 break;
3827 }
3828
3829 case Primitive::kPrimLong: {
3830 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01003831 locations->SetInAt(1, ArmEncodableConstantOrRegister(add->InputAt(1), ADD));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003832 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003833 break;
3834 }
3835
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003836 case Primitive::kPrimFloat:
3837 case Primitive::kPrimDouble: {
3838 locations->SetInAt(0, Location::RequiresFpuRegister());
3839 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003840 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003841 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003842 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003843
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003844 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003845 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003846 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003847}
3848
3849void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
3850 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003851 Location out = locations->Out();
3852 Location first = locations->InAt(0);
3853 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003854 switch (add->GetResultType()) {
3855 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003856 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003857 __ add(out.AsRegister<Register>(),
3858 first.AsRegister<Register>(),
3859 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003860 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003861 __ AddConstant(out.AsRegister<Register>(),
3862 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003863 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003864 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003865 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003866
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003867 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01003868 if (second.IsConstant()) {
3869 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
3870 GenerateAddLongConst(out, first, value);
3871 } else {
3872 DCHECK(second.IsRegisterPair());
3873 __ adds(out.AsRegisterPairLow<Register>(),
3874 first.AsRegisterPairLow<Register>(),
3875 ShifterOperand(second.AsRegisterPairLow<Register>()));
3876 __ adc(out.AsRegisterPairHigh<Register>(),
3877 first.AsRegisterPairHigh<Register>(),
3878 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3879 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003880 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003881 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003882
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003883 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00003884 __ vadds(out.AsFpuRegister<SRegister>(),
3885 first.AsFpuRegister<SRegister>(),
3886 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003887 break;
3888
3889 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003890 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3891 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3892 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003893 break;
3894
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003895 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003896 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003897 }
3898}
3899
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003900void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003901 LocationSummary* locations =
3902 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003903 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003904 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003905 locations->SetInAt(0, Location::RequiresRegister());
3906 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003907 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3908 break;
3909 }
3910
3911 case Primitive::kPrimLong: {
3912 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01003913 locations->SetInAt(1, ArmEncodableConstantOrRegister(sub->InputAt(1), SUB));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003914 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003915 break;
3916 }
Calin Juravle11351682014-10-23 15:38:15 +01003917 case Primitive::kPrimFloat:
3918 case Primitive::kPrimDouble: {
3919 locations->SetInAt(0, Location::RequiresFpuRegister());
3920 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003921 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003922 break;
Calin Juravle11351682014-10-23 15:38:15 +01003923 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003924 default:
Calin Juravle11351682014-10-23 15:38:15 +01003925 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003926 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003927}
3928
3929void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
3930 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01003931 Location out = locations->Out();
3932 Location first = locations->InAt(0);
3933 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003934 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003935 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01003936 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003937 __ sub(out.AsRegister<Register>(),
3938 first.AsRegister<Register>(),
3939 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003940 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003941 __ AddConstant(out.AsRegister<Register>(),
3942 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01003943 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003944 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003945 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003946 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003947
Calin Juravle11351682014-10-23 15:38:15 +01003948 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01003949 if (second.IsConstant()) {
3950 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
3951 GenerateAddLongConst(out, first, -value);
3952 } else {
3953 DCHECK(second.IsRegisterPair());
3954 __ subs(out.AsRegisterPairLow<Register>(),
3955 first.AsRegisterPairLow<Register>(),
3956 ShifterOperand(second.AsRegisterPairLow<Register>()));
3957 __ sbc(out.AsRegisterPairHigh<Register>(),
3958 first.AsRegisterPairHigh<Register>(),
3959 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3960 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003961 break;
Calin Juravle11351682014-10-23 15:38:15 +01003962 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003963
Calin Juravle11351682014-10-23 15:38:15 +01003964 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00003965 __ vsubs(out.AsFpuRegister<SRegister>(),
3966 first.AsFpuRegister<SRegister>(),
3967 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003968 break;
Calin Juravle11351682014-10-23 15:38:15 +01003969 }
3970
3971 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003972 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3973 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3974 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01003975 break;
3976 }
3977
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003978
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003979 default:
Calin Juravle11351682014-10-23 15:38:15 +01003980 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003981 }
3982}
3983
Calin Juravle34bacdf2014-10-07 20:23:36 +01003984void LocationsBuilderARM::VisitMul(HMul* mul) {
3985 LocationSummary* locations =
3986 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3987 switch (mul->GetResultType()) {
3988 case Primitive::kPrimInt:
3989 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003990 locations->SetInAt(0, Location::RequiresRegister());
3991 locations->SetInAt(1, Location::RequiresRegister());
3992 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01003993 break;
3994 }
3995
Calin Juravleb5bfa962014-10-21 18:02:24 +01003996 case Primitive::kPrimFloat:
3997 case Primitive::kPrimDouble: {
3998 locations->SetInAt(0, Location::RequiresFpuRegister());
3999 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004000 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01004001 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01004002 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01004003
4004 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01004005 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01004006 }
4007}
4008
4009void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
4010 LocationSummary* locations = mul->GetLocations();
4011 Location out = locations->Out();
4012 Location first = locations->InAt(0);
4013 Location second = locations->InAt(1);
4014 switch (mul->GetResultType()) {
4015 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00004016 __ mul(out.AsRegister<Register>(),
4017 first.AsRegister<Register>(),
4018 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01004019 break;
4020 }
4021 case Primitive::kPrimLong: {
4022 Register out_hi = out.AsRegisterPairHigh<Register>();
4023 Register out_lo = out.AsRegisterPairLow<Register>();
4024 Register in1_hi = first.AsRegisterPairHigh<Register>();
4025 Register in1_lo = first.AsRegisterPairLow<Register>();
4026 Register in2_hi = second.AsRegisterPairHigh<Register>();
4027 Register in2_lo = second.AsRegisterPairLow<Register>();
4028
4029 // Extra checks to protect caused by the existence of R1_R2.
4030 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
4031 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
4032 DCHECK_NE(out_hi, in1_lo);
4033 DCHECK_NE(out_hi, in2_lo);
4034
4035 // input: in1 - 64 bits, in2 - 64 bits
4036 // output: out
4037 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
4038 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
4039 // parts: out.lo = (in1.lo * in2.lo)[31:0]
4040
4041 // IP <- in1.lo * in2.hi
4042 __ mul(IP, in1_lo, in2_hi);
4043 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
4044 __ mla(out_hi, in1_hi, in2_lo, IP);
4045 // out.lo <- (in1.lo * in2.lo)[31:0];
4046 __ umull(out_lo, IP, in1_lo, in2_lo);
4047 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
4048 __ add(out_hi, out_hi, ShifterOperand(IP));
4049 break;
4050 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01004051
4052 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004053 __ vmuls(out.AsFpuRegister<SRegister>(),
4054 first.AsFpuRegister<SRegister>(),
4055 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01004056 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01004057 }
4058
4059 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004060 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4061 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4062 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01004063 break;
4064 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01004065
4066 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01004067 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01004068 }
4069}
4070
Zheng Xuc6667102015-05-15 16:08:45 +08004071void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
4072 DCHECK(instruction->IsDiv() || instruction->IsRem());
4073 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4074
4075 LocationSummary* locations = instruction->GetLocations();
4076 Location second = locations->InAt(1);
4077 DCHECK(second.IsConstant());
4078
4079 Register out = locations->Out().AsRegister<Register>();
4080 Register dividend = locations->InAt(0).AsRegister<Register>();
4081 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4082 DCHECK(imm == 1 || imm == -1);
4083
4084 if (instruction->IsRem()) {
4085 __ LoadImmediate(out, 0);
4086 } else {
4087 if (imm == 1) {
4088 __ Mov(out, dividend);
4089 } else {
4090 __ rsb(out, dividend, ShifterOperand(0));
4091 }
4092 }
4093}
4094
4095void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
4096 DCHECK(instruction->IsDiv() || instruction->IsRem());
4097 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4098
4099 LocationSummary* locations = instruction->GetLocations();
4100 Location second = locations->InAt(1);
4101 DCHECK(second.IsConstant());
4102
4103 Register out = locations->Out().AsRegister<Register>();
4104 Register dividend = locations->InAt(0).AsRegister<Register>();
4105 Register temp = locations->GetTemp(0).AsRegister<Register>();
4106 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004107 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08004108 int ctz_imm = CTZ(abs_imm);
4109
4110 if (ctz_imm == 1) {
4111 __ Lsr(temp, dividend, 32 - ctz_imm);
4112 } else {
4113 __ Asr(temp, dividend, 31);
4114 __ Lsr(temp, temp, 32 - ctz_imm);
4115 }
4116 __ add(out, temp, ShifterOperand(dividend));
4117
4118 if (instruction->IsDiv()) {
4119 __ Asr(out, out, ctz_imm);
4120 if (imm < 0) {
4121 __ rsb(out, out, ShifterOperand(0));
4122 }
4123 } else {
4124 __ ubfx(out, out, 0, ctz_imm);
4125 __ sub(out, out, ShifterOperand(temp));
4126 }
4127}
4128
4129void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
4130 DCHECK(instruction->IsDiv() || instruction->IsRem());
4131 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4132
4133 LocationSummary* locations = instruction->GetLocations();
4134 Location second = locations->InAt(1);
4135 DCHECK(second.IsConstant());
4136
4137 Register out = locations->Out().AsRegister<Register>();
4138 Register dividend = locations->InAt(0).AsRegister<Register>();
4139 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4140 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4141 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4142
4143 int64_t magic;
4144 int shift;
4145 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
4146
4147 __ LoadImmediate(temp1, magic);
4148 __ smull(temp2, temp1, dividend, temp1);
4149
4150 if (imm > 0 && magic < 0) {
4151 __ add(temp1, temp1, ShifterOperand(dividend));
4152 } else if (imm < 0 && magic > 0) {
4153 __ sub(temp1, temp1, ShifterOperand(dividend));
4154 }
4155
4156 if (shift != 0) {
4157 __ Asr(temp1, temp1, shift);
4158 }
4159
4160 if (instruction->IsDiv()) {
4161 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
4162 } else {
4163 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
4164 // TODO: Strength reduction for mls.
4165 __ LoadImmediate(temp2, imm);
4166 __ mls(out, temp1, temp2, dividend);
4167 }
4168}
4169
4170void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
4171 DCHECK(instruction->IsDiv() || instruction->IsRem());
4172 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4173
4174 LocationSummary* locations = instruction->GetLocations();
4175 Location second = locations->InAt(1);
4176 DCHECK(second.IsConstant());
4177
4178 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4179 if (imm == 0) {
4180 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
4181 } else if (imm == 1 || imm == -1) {
4182 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004183 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004184 DivRemByPowerOfTwo(instruction);
4185 } else {
4186 DCHECK(imm <= -2 || imm >= 2);
4187 GenerateDivRemWithAnyConstant(instruction);
4188 }
4189}
4190
Calin Juravle7c4954d2014-10-28 16:57:40 +00004191void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004192 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4193 if (div->GetResultType() == Primitive::kPrimLong) {
4194 // pLdiv runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004195 call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004196 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
4197 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004198 } else if (div->GetResultType() == Primitive::kPrimInt &&
4199 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4200 // pIdivmod runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004201 call_kind = LocationSummary::kCallOnMainOnly;
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004202 }
4203
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004204 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
4205
Calin Juravle7c4954d2014-10-28 16:57:40 +00004206 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004207 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004208 if (div->InputAt(1)->IsConstant()) {
4209 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004210 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004211 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004212 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
4213 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004214 // No temp register required.
4215 } else {
4216 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004217 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004218 locations->AddTemp(Location::RequiresRegister());
4219 }
4220 }
4221 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004222 locations->SetInAt(0, Location::RequiresRegister());
4223 locations->SetInAt(1, Location::RequiresRegister());
4224 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4225 } else {
4226 InvokeRuntimeCallingConvention calling_convention;
4227 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4228 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004229 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004230 // we only need the former.
4231 locations->SetOut(Location::RegisterLocation(R0));
4232 }
Calin Juravled0d48522014-11-04 16:40:20 +00004233 break;
4234 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00004235 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004236 InvokeRuntimeCallingConvention calling_convention;
4237 locations->SetInAt(0, Location::RegisterPairLocation(
4238 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4239 locations->SetInAt(1, Location::RegisterPairLocation(
4240 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004241 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00004242 break;
4243 }
4244 case Primitive::kPrimFloat:
4245 case Primitive::kPrimDouble: {
4246 locations->SetInAt(0, Location::RequiresFpuRegister());
4247 locations->SetInAt(1, Location::RequiresFpuRegister());
4248 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4249 break;
4250 }
4251
4252 default:
4253 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4254 }
4255}
4256
4257void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
4258 LocationSummary* locations = div->GetLocations();
4259 Location out = locations->Out();
4260 Location first = locations->InAt(0);
4261 Location second = locations->InAt(1);
4262
4263 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004264 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004265 if (second.IsConstant()) {
4266 GenerateDivRemConstantIntegral(div);
4267 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004268 __ sdiv(out.AsRegister<Register>(),
4269 first.AsRegister<Register>(),
4270 second.AsRegister<Register>());
4271 } else {
4272 InvokeRuntimeCallingConvention calling_convention;
4273 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4274 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4275 DCHECK_EQ(R0, out.AsRegister<Register>());
4276
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004277 codegen_->InvokeRuntime(kQuickIdivmod, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004278 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004279 }
Calin Juravled0d48522014-11-04 16:40:20 +00004280 break;
4281 }
4282
Calin Juravle7c4954d2014-10-28 16:57:40 +00004283 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004284 InvokeRuntimeCallingConvention calling_convention;
4285 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
4286 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
4287 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
4288 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
4289 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004290 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004291
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004292 codegen_->InvokeRuntime(kQuickLdiv, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004293 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00004294 break;
4295 }
4296
4297 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004298 __ vdivs(out.AsFpuRegister<SRegister>(),
4299 first.AsFpuRegister<SRegister>(),
4300 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004301 break;
4302 }
4303
4304 case Primitive::kPrimDouble: {
4305 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4306 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4307 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
4308 break;
4309 }
4310
4311 default:
4312 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4313 }
4314}
4315
Calin Juravlebacfec32014-11-14 15:54:36 +00004316void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004317 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004318
4319 // Most remainders are implemented in the runtime.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004320 LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004321 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
4322 // sdiv will be replaced by other instruction sequence.
4323 call_kind = LocationSummary::kNoCall;
4324 } else if ((rem->GetResultType() == Primitive::kPrimInt)
4325 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004326 // Have hardware divide instruction for int, do it with three instructions.
4327 call_kind = LocationSummary::kNoCall;
4328 }
4329
Calin Juravlebacfec32014-11-14 15:54:36 +00004330 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
4331
Calin Juravled2ec87d2014-12-08 14:24:46 +00004332 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004333 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004334 if (rem->InputAt(1)->IsConstant()) {
4335 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004336 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004337 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004338 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
4339 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004340 // No temp register required.
4341 } else {
4342 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004343 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004344 locations->AddTemp(Location::RequiresRegister());
4345 }
4346 }
4347 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004348 locations->SetInAt(0, Location::RequiresRegister());
4349 locations->SetInAt(1, Location::RequiresRegister());
4350 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4351 locations->AddTemp(Location::RequiresRegister());
4352 } else {
4353 InvokeRuntimeCallingConvention calling_convention;
4354 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4355 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004356 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004357 // we only need the latter.
4358 locations->SetOut(Location::RegisterLocation(R1));
4359 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004360 break;
4361 }
4362 case Primitive::kPrimLong: {
4363 InvokeRuntimeCallingConvention calling_convention;
4364 locations->SetInAt(0, Location::RegisterPairLocation(
4365 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4366 locations->SetInAt(1, Location::RegisterPairLocation(
4367 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4368 // The runtime helper puts the output in R2,R3.
4369 locations->SetOut(Location::RegisterPairLocation(R2, R3));
4370 break;
4371 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00004372 case Primitive::kPrimFloat: {
4373 InvokeRuntimeCallingConvention calling_convention;
4374 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
4375 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
4376 locations->SetOut(Location::FpuRegisterLocation(S0));
4377 break;
4378 }
4379
Calin Juravlebacfec32014-11-14 15:54:36 +00004380 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004381 InvokeRuntimeCallingConvention calling_convention;
4382 locations->SetInAt(0, Location::FpuRegisterPairLocation(
4383 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
4384 locations->SetInAt(1, Location::FpuRegisterPairLocation(
4385 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
4386 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00004387 break;
4388 }
4389
4390 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004391 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004392 }
4393}
4394
4395void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
4396 LocationSummary* locations = rem->GetLocations();
4397 Location out = locations->Out();
4398 Location first = locations->InAt(0);
4399 Location second = locations->InAt(1);
4400
Calin Juravled2ec87d2014-12-08 14:24:46 +00004401 Primitive::Type type = rem->GetResultType();
4402 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004403 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004404 if (second.IsConstant()) {
4405 GenerateDivRemConstantIntegral(rem);
4406 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004407 Register reg1 = first.AsRegister<Register>();
4408 Register reg2 = second.AsRegister<Register>();
4409 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004410
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004411 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004412 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004413 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004414 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004415 } else {
4416 InvokeRuntimeCallingConvention calling_convention;
4417 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4418 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4419 DCHECK_EQ(R1, out.AsRegister<Register>());
4420
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004421 codegen_->InvokeRuntime(kQuickIdivmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004422 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004423 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004424 break;
4425 }
4426
4427 case Primitive::kPrimLong: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004428 codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004429 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004430 break;
4431 }
4432
Calin Juravled2ec87d2014-12-08 14:24:46 +00004433 case Primitive::kPrimFloat: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004434 codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004435 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00004436 break;
4437 }
4438
Calin Juravlebacfec32014-11-14 15:54:36 +00004439 case Primitive::kPrimDouble: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004440 codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004441 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004442 break;
4443 }
4444
4445 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004446 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004447 }
4448}
4449
Calin Juravled0d48522014-11-04 16:40:20 +00004450void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004451 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004452 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00004453}
4454
4455void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01004456 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00004457 codegen_->AddSlowPath(slow_path);
4458
4459 LocationSummary* locations = instruction->GetLocations();
4460 Location value = locations->InAt(0);
4461
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004462 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00004463 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06004464 case Primitive::kPrimByte:
4465 case Primitive::kPrimChar:
4466 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004467 case Primitive::kPrimInt: {
4468 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004469 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004470 } else {
4471 DCHECK(value.IsConstant()) << value;
4472 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
4473 __ b(slow_path->GetEntryLabel());
4474 }
4475 }
4476 break;
4477 }
4478 case Primitive::kPrimLong: {
4479 if (value.IsRegisterPair()) {
4480 __ orrs(IP,
4481 value.AsRegisterPairLow<Register>(),
4482 ShifterOperand(value.AsRegisterPairHigh<Register>()));
4483 __ b(slow_path->GetEntryLabel(), EQ);
4484 } else {
4485 DCHECK(value.IsConstant()) << value;
4486 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4487 __ b(slow_path->GetEntryLabel());
4488 }
4489 }
4490 break;
4491 default:
4492 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
4493 }
4494 }
Calin Juravled0d48522014-11-04 16:40:20 +00004495}
4496
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004497void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
4498 Register in = locations->InAt(0).AsRegister<Register>();
4499 Location rhs = locations->InAt(1);
4500 Register out = locations->Out().AsRegister<Register>();
4501
4502 if (rhs.IsConstant()) {
4503 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
4504 // so map all rotations to a +ve. equivalent in that range.
4505 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
4506 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
4507 if (rot) {
4508 // Rotate, mapping left rotations to right equivalents if necessary.
4509 // (e.g. left by 2 bits == right by 30.)
4510 __ Ror(out, in, rot);
4511 } else if (out != in) {
4512 __ Mov(out, in);
4513 }
4514 } else {
4515 __ Ror(out, in, rhs.AsRegister<Register>());
4516 }
4517}
4518
4519// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
4520// rotates by swapping input regs (effectively rotating by the first 32-bits of
4521// a larger rotation) or flipping direction (thus treating larger right/left
4522// rotations as sub-word sized rotations in the other direction) as appropriate.
Anton Kirilov6f644202017-02-27 18:29:45 +00004523void InstructionCodeGeneratorARM::HandleLongRotate(HRor* ror) {
4524 LocationSummary* locations = ror->GetLocations();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004525 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
4526 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
4527 Location rhs = locations->InAt(1);
4528 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
4529 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
4530
4531 if (rhs.IsConstant()) {
4532 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
4533 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00004534 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004535 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
4536 // logic below to a simple pair of binary orr.
4537 // (e.g. 34 bits == in_reg swap + 2 bits right.)
4538 if (rot >= kArmBitsPerWord) {
4539 rot -= kArmBitsPerWord;
4540 std::swap(in_reg_hi, in_reg_lo);
4541 }
4542 // Rotate, or mov to out for zero or word size rotations.
4543 if (rot != 0u) {
4544 __ Lsr(out_reg_hi, in_reg_hi, rot);
4545 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
4546 __ Lsr(out_reg_lo, in_reg_lo, rot);
4547 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
4548 } else {
4549 __ Mov(out_reg_lo, in_reg_lo);
4550 __ Mov(out_reg_hi, in_reg_hi);
4551 }
4552 } else {
4553 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
4554 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
4555 Label end;
4556 Label shift_by_32_plus_shift_right;
Anton Kirilov6f644202017-02-27 18:29:45 +00004557 Label* final_label = codegen_->GetFinalLabel(ror, &end);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004558
4559 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
4560 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
4561 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
4562 __ b(&shift_by_32_plus_shift_right, CC);
4563
4564 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
4565 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
4566 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
4567 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4568 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4569 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4570 __ Lsr(shift_left, in_reg_hi, shift_right);
4571 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
Anton Kirilov6f644202017-02-27 18:29:45 +00004572 __ b(final_label);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004573
4574 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
4575 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
4576 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
4577 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
4578 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4579 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4580 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4581 __ Lsl(shift_right, in_reg_hi, shift_left);
4582 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
4583
Anton Kirilov6f644202017-02-27 18:29:45 +00004584 if (end.IsLinked()) {
4585 __ Bind(&end);
4586 }
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004587 }
4588}
Roland Levillain22c49222016-03-18 14:04:28 +00004589
4590void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004591 LocationSummary* locations =
4592 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
4593 switch (ror->GetResultType()) {
4594 case Primitive::kPrimInt: {
4595 locations->SetInAt(0, Location::RequiresRegister());
4596 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
4597 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4598 break;
4599 }
4600 case Primitive::kPrimLong: {
4601 locations->SetInAt(0, Location::RequiresRegister());
4602 if (ror->InputAt(1)->IsConstant()) {
4603 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
4604 } else {
4605 locations->SetInAt(1, Location::RequiresRegister());
4606 locations->AddTemp(Location::RequiresRegister());
4607 locations->AddTemp(Location::RequiresRegister());
4608 }
4609 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4610 break;
4611 }
4612 default:
4613 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4614 }
4615}
4616
Roland Levillain22c49222016-03-18 14:04:28 +00004617void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004618 LocationSummary* locations = ror->GetLocations();
4619 Primitive::Type type = ror->GetResultType();
4620 switch (type) {
4621 case Primitive::kPrimInt: {
4622 HandleIntegerRotate(locations);
4623 break;
4624 }
4625 case Primitive::kPrimLong: {
Anton Kirilov6f644202017-02-27 18:29:45 +00004626 HandleLongRotate(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004627 break;
4628 }
4629 default:
4630 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00004631 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004632 }
4633}
4634
Calin Juravle9aec02f2014-11-18 23:06:35 +00004635void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
4636 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4637
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004638 LocationSummary* locations =
4639 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004640
4641 switch (op->GetResultType()) {
4642 case Primitive::kPrimInt: {
4643 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004644 if (op->InputAt(1)->IsConstant()) {
4645 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4646 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4647 } else {
4648 locations->SetInAt(1, Location::RequiresRegister());
4649 // Make the output overlap, as it will be used to hold the masked
4650 // second input.
4651 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4652 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004653 break;
4654 }
4655 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004656 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004657 if (op->InputAt(1)->IsConstant()) {
4658 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4659 // For simplicity, use kOutputOverlap even though we only require that low registers
4660 // don't clash with high registers which the register allocator currently guarantees.
4661 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4662 } else {
4663 locations->SetInAt(1, Location::RequiresRegister());
4664 locations->AddTemp(Location::RequiresRegister());
4665 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4666 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004667 break;
4668 }
4669 default:
4670 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
4671 }
4672}
4673
4674void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
4675 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4676
4677 LocationSummary* locations = op->GetLocations();
4678 Location out = locations->Out();
4679 Location first = locations->InAt(0);
4680 Location second = locations->InAt(1);
4681
4682 Primitive::Type type = op->GetResultType();
4683 switch (type) {
4684 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004685 Register out_reg = out.AsRegister<Register>();
4686 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004687 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004688 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00004689 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00004690 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00004691 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01004692 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004693 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01004694 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004695 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01004696 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004697 }
4698 } else {
4699 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00004700 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00004701 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00004702 __ Mov(out_reg, first_reg);
4703 } else if (op->IsShl()) {
4704 __ Lsl(out_reg, first_reg, shift_value);
4705 } else if (op->IsShr()) {
4706 __ Asr(out_reg, first_reg, shift_value);
4707 } else {
4708 __ Lsr(out_reg, first_reg, shift_value);
4709 }
4710 }
4711 break;
4712 }
4713 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004714 Register o_h = out.AsRegisterPairHigh<Register>();
4715 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004716
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004717 Register high = first.AsRegisterPairHigh<Register>();
4718 Register low = first.AsRegisterPairLow<Register>();
4719
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004720 if (second.IsRegister()) {
4721 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004722
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004723 Register second_reg = second.AsRegister<Register>();
4724
4725 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004726 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004727 // Shift the high part
4728 __ Lsl(o_h, high, o_l);
4729 // Shift the low part and `or` what overflew on the high part
4730 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
4731 __ Lsr(temp, low, temp);
4732 __ orr(o_h, o_h, ShifterOperand(temp));
4733 // If the shift is > 32 bits, override the high part
4734 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
4735 __ it(PL);
4736 __ Lsl(o_h, low, temp, PL);
4737 // Shift the low part
4738 __ Lsl(o_l, low, o_l);
4739 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004740 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004741 // Shift the low part
4742 __ Lsr(o_l, low, o_h);
4743 // Shift the high part and `or` what underflew on the low part
4744 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
4745 __ Lsl(temp, high, temp);
4746 __ orr(o_l, o_l, ShifterOperand(temp));
4747 // If the shift is > 32 bits, override the low part
4748 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
4749 __ it(PL);
4750 __ Asr(o_l, high, temp, PL);
4751 // Shift the high part
4752 __ Asr(o_h, high, o_h);
4753 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004754 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004755 // same as Shr except we use `Lsr`s and not `Asr`s
4756 __ Lsr(o_l, low, o_h);
4757 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
4758 __ Lsl(temp, high, temp);
4759 __ orr(o_l, o_l, ShifterOperand(temp));
4760 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
4761 __ it(PL);
4762 __ Lsr(o_l, high, temp, PL);
4763 __ Lsr(o_h, high, o_h);
4764 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004765 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004766 // Register allocator doesn't create partial overlap.
4767 DCHECK_NE(o_l, high);
4768 DCHECK_NE(o_h, low);
4769 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00004770 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004771 if (shift_value > 32) {
4772 if (op->IsShl()) {
4773 __ Lsl(o_h, low, shift_value - 32);
4774 __ LoadImmediate(o_l, 0);
4775 } else if (op->IsShr()) {
4776 __ Asr(o_l, high, shift_value - 32);
4777 __ Asr(o_h, high, 31);
4778 } else {
4779 __ Lsr(o_l, high, shift_value - 32);
4780 __ LoadImmediate(o_h, 0);
4781 }
4782 } else if (shift_value == 32) {
4783 if (op->IsShl()) {
4784 __ mov(o_h, ShifterOperand(low));
4785 __ LoadImmediate(o_l, 0);
4786 } else if (op->IsShr()) {
4787 __ mov(o_l, ShifterOperand(high));
4788 __ Asr(o_h, high, 31);
4789 } else {
4790 __ mov(o_l, ShifterOperand(high));
4791 __ LoadImmediate(o_h, 0);
4792 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00004793 } else if (shift_value == 1) {
4794 if (op->IsShl()) {
4795 __ Lsls(o_l, low, 1);
4796 __ adc(o_h, high, ShifterOperand(high));
4797 } else if (op->IsShr()) {
4798 __ Asrs(o_h, high, 1);
4799 __ Rrx(o_l, low);
4800 } else {
4801 __ Lsrs(o_h, high, 1);
4802 __ Rrx(o_l, low);
4803 }
4804 } else {
4805 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004806 if (op->IsShl()) {
4807 __ Lsl(o_h, high, shift_value);
4808 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
4809 __ Lsl(o_l, low, shift_value);
4810 } else if (op->IsShr()) {
4811 __ Lsr(o_l, low, shift_value);
4812 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
4813 __ Asr(o_h, high, shift_value);
4814 } else {
4815 __ Lsr(o_l, low, shift_value);
4816 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
4817 __ Lsr(o_h, high, shift_value);
4818 }
4819 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004820 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004821 break;
4822 }
4823 default:
4824 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004825 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004826 }
4827}
4828
4829void LocationsBuilderARM::VisitShl(HShl* shl) {
4830 HandleShift(shl);
4831}
4832
4833void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
4834 HandleShift(shl);
4835}
4836
4837void LocationsBuilderARM::VisitShr(HShr* shr) {
4838 HandleShift(shr);
4839}
4840
4841void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
4842 HandleShift(shr);
4843}
4844
4845void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
4846 HandleShift(ushr);
4847}
4848
4849void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
4850 HandleShift(ushr);
4851}
4852
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004853void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004854 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004855 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
David Brazdil6de19382016-01-08 17:37:10 +00004856 if (instruction->IsStringAlloc()) {
4857 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
4858 } else {
4859 InvokeRuntimeCallingConvention calling_convention;
4860 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00004861 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004862 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004863}
4864
4865void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004866 // Note: if heap poisoning is enabled, the entry point takes cares
4867 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00004868 if (instruction->IsStringAlloc()) {
4869 // String is allocated through StringFactory. Call NewEmptyString entry point.
4870 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07004871 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00004872 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
4873 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
4874 __ blx(LR);
4875 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4876 } else {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004877 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00004878 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00004879 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004880}
4881
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004882void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
4883 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004884 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004885 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004886 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004887 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4888 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004889}
4890
4891void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004892 // Note: if heap poisoning is enabled, the entry point takes cares
4893 // of poisoning the reference.
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00004894 QuickEntrypointEnum entrypoint =
4895 CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
4896 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004897 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00004898 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004899}
4900
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004901void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004902 LocationSummary* locations =
4903 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004904 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4905 if (location.IsStackSlot()) {
4906 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4907 } else if (location.IsDoubleStackSlot()) {
4908 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004909 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004910 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004911}
4912
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004913void InstructionCodeGeneratorARM::VisitParameterValue(
4914 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004915 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004916}
4917
4918void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
4919 LocationSummary* locations =
4920 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4921 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4922}
4923
4924void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4925 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004926}
4927
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004928void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004929 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004930 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004931 locations->SetInAt(0, Location::RequiresRegister());
4932 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004933}
4934
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004935void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
4936 LocationSummary* locations = not_->GetLocations();
4937 Location out = locations->Out();
4938 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00004939 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004940 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004941 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004942 break;
4943
4944 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01004945 __ mvn(out.AsRegisterPairLow<Register>(),
4946 ShifterOperand(in.AsRegisterPairLow<Register>()));
4947 __ mvn(out.AsRegisterPairHigh<Register>(),
4948 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004949 break;
4950
4951 default:
4952 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4953 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004954}
4955
David Brazdil66d126e2015-04-03 16:02:44 +01004956void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
4957 LocationSummary* locations =
4958 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4959 locations->SetInAt(0, Location::RequiresRegister());
4960 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4961}
4962
4963void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01004964 LocationSummary* locations = bool_not->GetLocations();
4965 Location out = locations->Out();
4966 Location in = locations->InAt(0);
4967 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
4968}
4969
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004970void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004971 LocationSummary* locations =
4972 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00004973 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00004974 case Primitive::kPrimBoolean:
4975 case Primitive::kPrimByte:
4976 case Primitive::kPrimShort:
4977 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08004978 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00004979 case Primitive::kPrimLong: {
4980 locations->SetInAt(0, Location::RequiresRegister());
4981 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004982 // Output overlaps because it is written before doing the low comparison.
4983 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00004984 break;
4985 }
4986 case Primitive::kPrimFloat:
4987 case Primitive::kPrimDouble: {
4988 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004989 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00004990 locations->SetOut(Location::RequiresRegister());
4991 break;
4992 }
4993 default:
4994 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
4995 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004996}
4997
4998void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004999 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005000 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00005001 Location left = locations->InAt(0);
5002 Location right = locations->InAt(1);
5003
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005004 Label less, greater, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00005005 Label* final_label = codegen_->GetFinalLabel(compare, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00005006 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00005007 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00005008 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00005009 case Primitive::kPrimBoolean:
5010 case Primitive::kPrimByte:
5011 case Primitive::kPrimShort:
5012 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08005013 case Primitive::kPrimInt: {
5014 __ LoadImmediate(out, 0);
5015 __ cmp(left.AsRegister<Register>(),
5016 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
5017 less_cond = LT;
5018 break;
5019 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005020 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005021 __ cmp(left.AsRegisterPairHigh<Register>(),
5022 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005023 __ b(&less, LT);
5024 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01005025 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00005026 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005027 __ cmp(left.AsRegisterPairLow<Register>(),
5028 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00005029 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00005030 break;
5031 }
5032 case Primitive::kPrimFloat:
5033 case Primitive::kPrimDouble: {
5034 __ LoadImmediate(out, 0);
Donghui Bai426b49c2016-11-08 14:55:38 +08005035 GenerateVcmp(compare, codegen_);
Calin Juravleddb7df22014-11-25 20:56:51 +00005036 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00005037 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005038 break;
5039 }
5040 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00005041 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00005042 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005043 }
Aart Bika19616e2016-02-01 18:57:58 -08005044
Anton Kirilov6f644202017-02-27 18:29:45 +00005045 __ b(final_label, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00005046 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00005047
5048 __ Bind(&greater);
5049 __ LoadImmediate(out, 1);
Anton Kirilov6f644202017-02-27 18:29:45 +00005050 __ b(final_label);
Calin Juravleddb7df22014-11-25 20:56:51 +00005051
5052 __ Bind(&less);
5053 __ LoadImmediate(out, -1);
5054
Anton Kirilov6f644202017-02-27 18:29:45 +00005055 if (done.IsLinked()) {
5056 __ Bind(&done);
5057 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005058}
5059
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005060void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005061 LocationSummary* locations =
5062 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01005063 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01005064 locations->SetInAt(i, Location::Any());
5065 }
5066 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005067}
5068
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005069void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005070 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005071}
5072
Roland Levillainc9285912015-12-18 10:38:42 +00005073void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
5074 // TODO (ported from quick): revisit ARM barrier kinds.
5075 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00005076 switch (kind) {
5077 case MemBarrierKind::kAnyStore:
5078 case MemBarrierKind::kLoadAny:
5079 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005080 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00005081 break;
5082 }
5083 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005084 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00005085 break;
5086 }
5087 default:
5088 LOG(FATAL) << "Unexpected memory barrier " << kind;
5089 }
Kenny Root1d8199d2015-06-02 11:01:10 -07005090 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00005091}
5092
5093void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
5094 uint32_t offset,
5095 Register out_lo,
5096 Register out_hi) {
5097 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005098 // Ensure `out_lo` is different from `addr`, so that loading
5099 // `offset` into `out_lo` does not clutter `addr`.
5100 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00005101 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005102 __ add(IP, addr, ShifterOperand(out_lo));
5103 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005104 }
5105 __ ldrexd(out_lo, out_hi, addr);
5106}
5107
5108void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
5109 uint32_t offset,
5110 Register value_lo,
5111 Register value_hi,
5112 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00005113 Register temp2,
5114 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005115 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00005116 if (offset != 0) {
5117 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005118 __ add(IP, addr, ShifterOperand(temp1));
5119 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005120 }
5121 __ Bind(&fail);
5122 // We need a load followed by store. (The address used in a STREX instruction must
5123 // be the same as the address in the most recently executed LDREX instruction.)
5124 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00005125 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005126 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005127 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00005128}
5129
5130void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5131 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5132
Nicolas Geoffray39468442014-09-02 15:17:15 +01005133 LocationSummary* locations =
5134 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005135 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005136
Calin Juravle52c48962014-12-16 17:02:57 +00005137 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005138 if (Primitive::IsFloatingPointType(field_type)) {
5139 locations->SetInAt(1, Location::RequiresFpuRegister());
5140 } else {
5141 locations->SetInAt(1, Location::RequiresRegister());
5142 }
5143
Calin Juravle52c48962014-12-16 17:02:57 +00005144 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00005145 bool generate_volatile = field_info.IsVolatile()
5146 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005147 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01005148 bool needs_write_barrier =
5149 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005150 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00005151 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01005152 if (needs_write_barrier) {
5153 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005154 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005155 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005156 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005157 // - registers need to be consecutive
5158 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005159 // We don't test for ARM yet, and the assertion makes sure that we
5160 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005161 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5162
5163 locations->AddTemp(Location::RequiresRegister());
5164 locations->AddTemp(Location::RequiresRegister());
5165 if (field_type == Primitive::kPrimDouble) {
5166 // For doubles we need two more registers to copy the value.
5167 locations->AddTemp(Location::RegisterLocation(R2));
5168 locations->AddTemp(Location::RegisterLocation(R3));
5169 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005170 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005171}
5172
Calin Juravle52c48962014-12-16 17:02:57 +00005173void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005174 const FieldInfo& field_info,
5175 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00005176 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5177
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005178 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00005179 Register base = locations->InAt(0).AsRegister<Register>();
5180 Location value = locations->InAt(1);
5181
5182 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005183 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005184 Primitive::Type field_type = field_info.GetFieldType();
5185 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01005186 bool needs_write_barrier =
5187 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00005188
5189 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005190 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00005191 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005192
5193 switch (field_type) {
5194 case Primitive::kPrimBoolean:
5195 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00005196 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005197 break;
5198 }
5199
5200 case Primitive::kPrimShort:
5201 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00005202 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005203 break;
5204 }
5205
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005206 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005207 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01005208 if (kPoisonHeapReferences && needs_write_barrier) {
5209 // Note that in the case where `value` is a null reference,
5210 // we do not enter this block, as a null reference does not
5211 // need poisoning.
5212 DCHECK_EQ(field_type, Primitive::kPrimNot);
5213 Register temp = locations->GetTemp(0).AsRegister<Register>();
5214 __ Mov(temp, value.AsRegister<Register>());
5215 __ PoisonHeapReference(temp);
5216 __ StoreToOffset(kStoreWord, temp, base, offset);
5217 } else {
5218 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
5219 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005220 break;
5221 }
5222
5223 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00005224 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005225 GenerateWideAtomicStore(base, offset,
5226 value.AsRegisterPairLow<Register>(),
5227 value.AsRegisterPairHigh<Register>(),
5228 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005229 locations->GetTemp(1).AsRegister<Register>(),
5230 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005231 } else {
5232 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005233 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005234 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005235 break;
5236 }
5237
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005238 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00005239 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005240 break;
5241 }
5242
5243 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005244 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005245 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005246 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
5247 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
5248
5249 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
5250
5251 GenerateWideAtomicStore(base, offset,
5252 value_reg_lo,
5253 value_reg_hi,
5254 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005255 locations->GetTemp(3).AsRegister<Register>(),
5256 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005257 } else {
5258 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005259 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005260 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005261 break;
5262 }
5263
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005264 case Primitive::kPrimVoid:
5265 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005266 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005267 }
Calin Juravle52c48962014-12-16 17:02:57 +00005268
Calin Juravle77520bc2015-01-12 18:45:46 +00005269 // Longs and doubles are handled in the switch.
5270 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
5271 codegen_->MaybeRecordImplicitNullCheck(instruction);
5272 }
5273
5274 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
5275 Register temp = locations->GetTemp(0).AsRegister<Register>();
5276 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005277 codegen_->MarkGCCard(
5278 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00005279 }
5280
Calin Juravle52c48962014-12-16 17:02:57 +00005281 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005282 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00005283 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005284}
5285
Calin Juravle52c48962014-12-16 17:02:57 +00005286void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
5287 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00005288
5289 bool object_field_get_with_read_barrier =
5290 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005291 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00005292 new (GetGraph()->GetArena()) LocationSummary(instruction,
5293 object_field_get_with_read_barrier ?
5294 LocationSummary::kCallOnSlowPath :
5295 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005296 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005297 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005298 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005299 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00005300
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005301 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00005302 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005303 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00005304 // The output overlaps in case of volatile long: we don't want the
5305 // code generated by GenerateWideAtomicLoad to overwrite the
5306 // object's location. Likewise, in the case of an object field get
5307 // with read barriers enabled, we do not want the load to overwrite
5308 // the object's location, as we need it to emit the read barrier.
5309 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
5310 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01005311
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005312 if (Primitive::IsFloatingPointType(instruction->GetType())) {
5313 locations->SetOut(Location::RequiresFpuRegister());
5314 } else {
5315 locations->SetOut(Location::RequiresRegister(),
5316 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
5317 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005318 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00005319 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005320 // - registers need to be consecutive
5321 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005322 // We don't test for ARM yet, and the assertion makes sure that we
5323 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005324 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5325 locations->AddTemp(Location::RequiresRegister());
5326 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00005327 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
5328 // We need a temporary register for the read barrier marking slow
5329 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01005330 if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
5331 !Runtime::Current()->UseJitCompilation()) {
5332 // If link-time thunks for the Baker read barrier are enabled, for AOT
5333 // loads we need a temporary only if the offset is too big.
5334 if (field_info.GetFieldOffset().Uint32Value() >= kReferenceLoadMinFarOffset) {
5335 locations->AddTemp(Location::RequiresRegister());
5336 }
5337 // And we always need the reserved entrypoint register.
5338 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
5339 } else {
5340 locations->AddTemp(Location::RequiresRegister());
5341 }
Calin Juravle52c48962014-12-16 17:02:57 +00005342 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005343}
5344
Vladimir Marko37dd80d2016-08-01 17:41:45 +01005345Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
5346 DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
5347 << input->GetType();
5348 if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
5349 (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
5350 return Location::ConstantLocation(input->AsConstant());
5351 } else {
5352 return Location::RequiresFpuRegister();
5353 }
5354}
5355
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005356Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
5357 Opcode opcode) {
5358 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
5359 if (constant->IsConstant() &&
5360 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
5361 return Location::ConstantLocation(constant->AsConstant());
5362 }
5363 return Location::RequiresRegister();
5364}
5365
5366bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
5367 Opcode opcode) {
5368 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
5369 if (Primitive::Is64BitType(input_cst->GetType())) {
Vladimir Marko59751a72016-08-05 14:37:27 +01005370 Opcode high_opcode = opcode;
5371 SetCc low_set_cc = kCcDontCare;
5372 switch (opcode) {
5373 case SUB:
5374 // Flip the operation to an ADD.
5375 value = -value;
5376 opcode = ADD;
5377 FALLTHROUGH_INTENDED;
5378 case ADD:
5379 if (Low32Bits(value) == 0u) {
5380 return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
5381 }
5382 high_opcode = ADC;
5383 low_set_cc = kCcSet;
5384 break;
5385 default:
5386 break;
5387 }
5388 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
5389 CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005390 } else {
5391 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
5392 }
5393}
5394
Vladimir Marko59751a72016-08-05 14:37:27 +01005395bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
5396 Opcode opcode,
5397 SetCc set_cc) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005398 ShifterOperand so;
5399 ArmAssembler* assembler = codegen_->GetAssembler();
Vladimir Marko59751a72016-08-05 14:37:27 +01005400 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005401 return true;
5402 }
5403 Opcode neg_opcode = kNoOperand;
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005404 uint32_t neg_value = 0;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005405 switch (opcode) {
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005406 case AND: neg_opcode = BIC; neg_value = ~value; break;
5407 case ORR: neg_opcode = ORN; neg_value = ~value; break;
5408 case ADD: neg_opcode = SUB; neg_value = -value; break;
5409 case ADC: neg_opcode = SBC; neg_value = ~value; break;
5410 case SUB: neg_opcode = ADD; neg_value = -value; break;
5411 case SBC: neg_opcode = ADC; neg_value = ~value; break;
5412 case MOV: neg_opcode = MVN; neg_value = ~value; break;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005413 default:
5414 return false;
5415 }
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005416
5417 if (assembler->ShifterOperandCanHold(kNoRegister,
5418 kNoRegister,
5419 neg_opcode,
5420 neg_value,
5421 set_cc,
5422 &so)) {
5423 return true;
5424 }
5425
5426 return opcode == AND && IsPowerOfTwo(value + 1);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005427}
5428
Calin Juravle52c48962014-12-16 17:02:57 +00005429void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
5430 const FieldInfo& field_info) {
5431 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005432
Calin Juravle52c48962014-12-16 17:02:57 +00005433 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005434 Location base_loc = locations->InAt(0);
5435 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00005436 Location out = locations->Out();
5437 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005438 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005439 Primitive::Type field_type = field_info.GetFieldType();
5440 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5441
5442 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00005443 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00005444 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005445 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005446
Roland Levillainc9285912015-12-18 10:38:42 +00005447 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00005448 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005449 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005450
Roland Levillainc9285912015-12-18 10:38:42 +00005451 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00005452 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005453 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005454
Roland Levillainc9285912015-12-18 10:38:42 +00005455 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00005456 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005457 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005458
5459 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00005460 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005461 break;
Roland Levillainc9285912015-12-18 10:38:42 +00005462
5463 case Primitive::kPrimNot: {
5464 // /* HeapReference<Object> */ out = *(base + offset)
5465 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5466 Location temp_loc = locations->GetTemp(0);
5467 // Note that a potential implicit null check is handled in this
5468 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
5469 codegen_->GenerateFieldLoadWithBakerReadBarrier(
5470 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
5471 if (is_volatile) {
5472 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5473 }
5474 } else {
5475 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
5476 codegen_->MaybeRecordImplicitNullCheck(instruction);
5477 if (is_volatile) {
5478 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5479 }
5480 // If read barriers are enabled, emit read barriers other than
5481 // Baker's using a slow path (and also unpoison the loaded
5482 // reference, if heap poisoning is enabled).
5483 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
5484 }
5485 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005486 }
5487
Roland Levillainc9285912015-12-18 10:38:42 +00005488 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00005489 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005490 GenerateWideAtomicLoad(base, offset,
5491 out.AsRegisterPairLow<Register>(),
5492 out.AsRegisterPairHigh<Register>());
5493 } else {
5494 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
5495 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005496 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005497
Roland Levillainc9285912015-12-18 10:38:42 +00005498 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00005499 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005500 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005501
5502 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005503 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005504 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005505 Register lo = locations->GetTemp(0).AsRegister<Register>();
5506 Register hi = locations->GetTemp(1).AsRegister<Register>();
5507 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00005508 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005509 __ vmovdrr(out_reg, lo, hi);
5510 } else {
5511 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005512 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005513 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005514 break;
5515 }
5516
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005517 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00005518 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005519 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005520 }
Calin Juravle52c48962014-12-16 17:02:57 +00005521
Roland Levillainc9285912015-12-18 10:38:42 +00005522 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
5523 // Potential implicit null checks, in the case of reference or
5524 // double fields, are handled in the previous switch statement.
5525 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00005526 codegen_->MaybeRecordImplicitNullCheck(instruction);
5527 }
5528
Calin Juravle52c48962014-12-16 17:02:57 +00005529 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005530 if (field_type == Primitive::kPrimNot) {
5531 // Memory barriers, in the case of references, are also handled
5532 // in the previous switch statement.
5533 } else {
5534 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5535 }
Roland Levillain4d027112015-07-01 15:41:14 +01005536 }
Calin Juravle52c48962014-12-16 17:02:57 +00005537}
5538
5539void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
5540 HandleFieldSet(instruction, instruction->GetFieldInfo());
5541}
5542
5543void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005544 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00005545}
5546
5547void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5548 HandleFieldGet(instruction, instruction->GetFieldInfo());
5549}
5550
5551void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5552 HandleFieldGet(instruction, instruction->GetFieldInfo());
5553}
5554
5555void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5556 HandleFieldGet(instruction, instruction->GetFieldInfo());
5557}
5558
5559void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5560 HandleFieldGet(instruction, instruction->GetFieldInfo());
5561}
5562
5563void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5564 HandleFieldSet(instruction, instruction->GetFieldInfo());
5565}
5566
5567void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005568 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005569}
5570
Calin Juravlee460d1d2015-09-29 04:52:17 +01005571void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
5572 HUnresolvedInstanceFieldGet* instruction) {
5573 FieldAccessCallingConventionARM calling_convention;
5574 codegen_->CreateUnresolvedFieldLocationSummary(
5575 instruction, instruction->GetFieldType(), calling_convention);
5576}
5577
5578void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
5579 HUnresolvedInstanceFieldGet* instruction) {
5580 FieldAccessCallingConventionARM calling_convention;
5581 codegen_->GenerateUnresolvedFieldAccess(instruction,
5582 instruction->GetFieldType(),
5583 instruction->GetFieldIndex(),
5584 instruction->GetDexPc(),
5585 calling_convention);
5586}
5587
5588void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
5589 HUnresolvedInstanceFieldSet* instruction) {
5590 FieldAccessCallingConventionARM calling_convention;
5591 codegen_->CreateUnresolvedFieldLocationSummary(
5592 instruction, instruction->GetFieldType(), calling_convention);
5593}
5594
5595void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
5596 HUnresolvedInstanceFieldSet* instruction) {
5597 FieldAccessCallingConventionARM calling_convention;
5598 codegen_->GenerateUnresolvedFieldAccess(instruction,
5599 instruction->GetFieldType(),
5600 instruction->GetFieldIndex(),
5601 instruction->GetDexPc(),
5602 calling_convention);
5603}
5604
5605void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
5606 HUnresolvedStaticFieldGet* instruction) {
5607 FieldAccessCallingConventionARM calling_convention;
5608 codegen_->CreateUnresolvedFieldLocationSummary(
5609 instruction, instruction->GetFieldType(), calling_convention);
5610}
5611
5612void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
5613 HUnresolvedStaticFieldGet* instruction) {
5614 FieldAccessCallingConventionARM calling_convention;
5615 codegen_->GenerateUnresolvedFieldAccess(instruction,
5616 instruction->GetFieldType(),
5617 instruction->GetFieldIndex(),
5618 instruction->GetDexPc(),
5619 calling_convention);
5620}
5621
5622void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
5623 HUnresolvedStaticFieldSet* instruction) {
5624 FieldAccessCallingConventionARM calling_convention;
5625 codegen_->CreateUnresolvedFieldLocationSummary(
5626 instruction, instruction->GetFieldType(), calling_convention);
5627}
5628
5629void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
5630 HUnresolvedStaticFieldSet* instruction) {
5631 FieldAccessCallingConventionARM calling_convention;
5632 codegen_->GenerateUnresolvedFieldAccess(instruction,
5633 instruction->GetFieldType(),
5634 instruction->GetFieldIndex(),
5635 instruction->GetDexPc(),
5636 calling_convention);
5637}
5638
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005639void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005640 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
5641 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005642}
5643
Calin Juravle2ae48182016-03-16 14:05:09 +00005644void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
5645 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005646 return;
5647 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005648 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00005649
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005650 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00005651 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005652}
5653
Calin Juravle2ae48182016-03-16 14:05:09 +00005654void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01005655 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00005656 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005657
5658 LocationSummary* locations = instruction->GetLocations();
5659 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005660
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005661 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005662}
5663
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005664void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00005665 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005666}
5667
Artem Serov6c916792016-07-11 14:02:34 +01005668static LoadOperandType GetLoadOperandType(Primitive::Type type) {
5669 switch (type) {
5670 case Primitive::kPrimNot:
5671 return kLoadWord;
5672 case Primitive::kPrimBoolean:
5673 return kLoadUnsignedByte;
5674 case Primitive::kPrimByte:
5675 return kLoadSignedByte;
5676 case Primitive::kPrimChar:
5677 return kLoadUnsignedHalfword;
5678 case Primitive::kPrimShort:
5679 return kLoadSignedHalfword;
5680 case Primitive::kPrimInt:
5681 return kLoadWord;
5682 case Primitive::kPrimLong:
5683 return kLoadWordPair;
5684 case Primitive::kPrimFloat:
5685 return kLoadSWord;
5686 case Primitive::kPrimDouble:
5687 return kLoadDWord;
5688 default:
5689 LOG(FATAL) << "Unreachable type " << type;
5690 UNREACHABLE();
5691 }
5692}
5693
5694static StoreOperandType GetStoreOperandType(Primitive::Type type) {
5695 switch (type) {
5696 case Primitive::kPrimNot:
5697 return kStoreWord;
5698 case Primitive::kPrimBoolean:
5699 case Primitive::kPrimByte:
5700 return kStoreByte;
5701 case Primitive::kPrimChar:
5702 case Primitive::kPrimShort:
5703 return kStoreHalfword;
5704 case Primitive::kPrimInt:
5705 return kStoreWord;
5706 case Primitive::kPrimLong:
5707 return kStoreWordPair;
5708 case Primitive::kPrimFloat:
5709 return kStoreSWord;
5710 case Primitive::kPrimDouble:
5711 return kStoreDWord;
5712 default:
5713 LOG(FATAL) << "Unreachable type " << type;
5714 UNREACHABLE();
5715 }
5716}
5717
5718void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
5719 Location out_loc,
5720 Register base,
5721 Register reg_offset,
5722 Condition cond) {
5723 uint32_t shift_count = Primitive::ComponentSizeShift(type);
5724 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
5725
5726 switch (type) {
5727 case Primitive::kPrimByte:
5728 __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
5729 break;
5730 case Primitive::kPrimBoolean:
5731 __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
5732 break;
5733 case Primitive::kPrimShort:
5734 __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
5735 break;
5736 case Primitive::kPrimChar:
5737 __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
5738 break;
5739 case Primitive::kPrimNot:
5740 case Primitive::kPrimInt:
5741 __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
5742 break;
5743 // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
5744 case Primitive::kPrimLong:
5745 case Primitive::kPrimFloat:
5746 case Primitive::kPrimDouble:
5747 default:
5748 LOG(FATAL) << "Unreachable type " << type;
5749 UNREACHABLE();
5750 }
5751}
5752
5753void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
5754 Location loc,
5755 Register base,
5756 Register reg_offset,
5757 Condition cond) {
5758 uint32_t shift_count = Primitive::ComponentSizeShift(type);
5759 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
5760
5761 switch (type) {
5762 case Primitive::kPrimByte:
5763 case Primitive::kPrimBoolean:
5764 __ strb(loc.AsRegister<Register>(), mem_address, cond);
5765 break;
5766 case Primitive::kPrimShort:
5767 case Primitive::kPrimChar:
5768 __ strh(loc.AsRegister<Register>(), mem_address, cond);
5769 break;
5770 case Primitive::kPrimNot:
5771 case Primitive::kPrimInt:
5772 __ str(loc.AsRegister<Register>(), mem_address, cond);
5773 break;
5774 // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
5775 case Primitive::kPrimLong:
5776 case Primitive::kPrimFloat:
5777 case Primitive::kPrimDouble:
5778 default:
5779 LOG(FATAL) << "Unreachable type " << type;
5780 UNREACHABLE();
5781 }
5782}
5783
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005784void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005785 bool object_array_get_with_read_barrier =
5786 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005787 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00005788 new (GetGraph()->GetArena()) LocationSummary(instruction,
5789 object_array_get_with_read_barrier ?
5790 LocationSummary::kCallOnSlowPath :
5791 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005792 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005793 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005794 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005795 locations->SetInAt(0, Location::RequiresRegister());
5796 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005797 if (Primitive::IsFloatingPointType(instruction->GetType())) {
5798 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5799 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00005800 // The output overlaps in the case of an object array get with
5801 // read barriers enabled: we do not want the move to overwrite the
5802 // array's location, as we need it to emit the read barrier.
5803 locations->SetOut(
5804 Location::RequiresRegister(),
5805 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005806 }
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01005807 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
5808 // We need a temporary register for the read barrier marking slow
5809 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
5810 if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
5811 !Runtime::Current()->UseJitCompilation() &&
5812 instruction->GetIndex()->IsConstant()) {
5813 // Array loads with constant index are treated as field loads.
5814 // If link-time thunks for the Baker read barrier are enabled, for AOT
5815 // constant index loads we need a temporary only if the offset is too big.
5816 uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
5817 uint32_t index = instruction->GetIndex()->AsIntConstant()->GetValue();
5818 offset += index << Primitive::ComponentSizeShift(Primitive::kPrimNot);
5819 if (offset >= kReferenceLoadMinFarOffset) {
5820 locations->AddTemp(Location::RequiresRegister());
5821 }
5822 // And we always need the reserved entrypoint register.
5823 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
5824 } else if (kBakerReadBarrierLinkTimeThunksEnableForArrays &&
5825 !Runtime::Current()->UseJitCompilation() &&
5826 !instruction->GetIndex()->IsConstant()) {
5827 // We need a non-scratch temporary for the array data pointer.
5828 locations->AddTemp(Location::RequiresRegister());
5829 // And we always need the reserved entrypoint register.
5830 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
5831 } else {
5832 locations->AddTemp(Location::RequiresRegister());
5833 }
5834 } else if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
5835 // Also need a temporary for String compression feature.
Roland Levillainc9285912015-12-18 10:38:42 +00005836 locations->AddTemp(Location::RequiresRegister());
5837 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005838}
5839
5840void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
5841 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005842 Location obj_loc = locations->InAt(0);
5843 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005844 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00005845 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01005846 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Roland Levillainc9285912015-12-18 10:38:42 +00005847 Primitive::Type type = instruction->GetType();
jessicahandojo05765752016-09-09 19:01:32 -07005848 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
5849 instruction->IsStringCharAt();
Artem Serov328429f2016-07-06 16:23:04 +01005850 HInstruction* array_instr = instruction->GetArray();
5851 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Artem Serov6c916792016-07-11 14:02:34 +01005852
Roland Levillain4d027112015-07-01 15:41:14 +01005853 switch (type) {
Artem Serov6c916792016-07-11 14:02:34 +01005854 case Primitive::kPrimBoolean:
5855 case Primitive::kPrimByte:
5856 case Primitive::kPrimShort:
5857 case Primitive::kPrimChar:
Roland Levillainc9285912015-12-18 10:38:42 +00005858 case Primitive::kPrimInt: {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005859 Register length;
5860 if (maybe_compressed_char_at) {
5861 length = locations->GetTemp(0).AsRegister<Register>();
5862 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
5863 __ LoadFromOffset(kLoadWord, length, obj, count_offset);
5864 codegen_->MaybeRecordImplicitNullCheck(instruction);
5865 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005866 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01005867 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
jessicahandojo05765752016-09-09 19:01:32 -07005868 if (maybe_compressed_char_at) {
jessicahandojo05765752016-09-09 19:01:32 -07005869 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00005870 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005871 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
5872 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
5873 "Expecting 0=compressed, 1=uncompressed");
5874 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07005875 __ LoadFromOffset(kLoadUnsignedByte,
5876 out_loc.AsRegister<Register>(),
5877 obj,
5878 data_offset + const_index);
Anton Kirilov6f644202017-02-27 18:29:45 +00005879 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07005880 __ Bind(&uncompressed_load);
5881 __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
5882 out_loc.AsRegister<Register>(),
5883 obj,
5884 data_offset + (const_index << 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00005885 if (done.IsLinked()) {
5886 __ Bind(&done);
5887 }
jessicahandojo05765752016-09-09 19:01:32 -07005888 } else {
5889 uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
Artem Serov6c916792016-07-11 14:02:34 +01005890
jessicahandojo05765752016-09-09 19:01:32 -07005891 LoadOperandType load_type = GetLoadOperandType(type);
5892 __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
5893 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005894 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005895 Register temp = IP;
5896
5897 if (has_intermediate_address) {
5898 // We do not need to compute the intermediate address from the array: the
5899 // input instruction has done it already. See the comment in
5900 // `TryExtractArrayAccessAddress()`.
5901 if (kIsDebugBuild) {
5902 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5903 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5904 }
5905 temp = obj;
5906 } else {
5907 __ add(temp, obj, ShifterOperand(data_offset));
5908 }
jessicahandojo05765752016-09-09 19:01:32 -07005909 if (maybe_compressed_char_at) {
5910 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00005911 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005912 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
5913 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
5914 "Expecting 0=compressed, 1=uncompressed");
5915 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07005916 __ ldrb(out_loc.AsRegister<Register>(),
5917 Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
Anton Kirilov6f644202017-02-27 18:29:45 +00005918 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07005919 __ Bind(&uncompressed_load);
5920 __ ldrh(out_loc.AsRegister<Register>(),
5921 Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00005922 if (done.IsLinked()) {
5923 __ Bind(&done);
5924 }
jessicahandojo05765752016-09-09 19:01:32 -07005925 } else {
5926 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
5927 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005928 }
5929 break;
5930 }
5931
Roland Levillainc9285912015-12-18 10:38:42 +00005932 case Primitive::kPrimNot: {
Roland Levillain19c54192016-11-04 13:44:09 +00005933 // The read barrier instrumentation of object ArrayGet
5934 // instructions does not support the HIntermediateAddress
5935 // instruction.
5936 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
5937
Roland Levillainc9285912015-12-18 10:38:42 +00005938 static_assert(
5939 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
5940 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00005941 // /* HeapReference<Object> */ out =
5942 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
5943 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5944 Location temp = locations->GetTemp(0);
5945 // Note that a potential implicit null check is handled in this
5946 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01005947 DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
5948 if (index.IsConstant()) {
5949 // Array load with a constant index can be treated as a field load.
5950 data_offset += helpers::Int32ConstantFrom(index) << Primitive::ComponentSizeShift(type);
5951 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
5952 out_loc,
5953 obj,
5954 data_offset,
5955 locations->GetTemp(0),
5956 /* needs_null_check */ false);
5957 } else {
5958 codegen_->GenerateArrayLoadWithBakerReadBarrier(
5959 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ false);
5960 }
Roland Levillainc9285912015-12-18 10:38:42 +00005961 } else {
5962 Register out = out_loc.AsRegister<Register>();
5963 if (index.IsConstant()) {
5964 size_t offset =
5965 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5966 __ LoadFromOffset(kLoadWord, out, obj, offset);
5967 codegen_->MaybeRecordImplicitNullCheck(instruction);
5968 // If read barriers are enabled, emit read barriers other than
5969 // Baker's using a slow path (and also unpoison the loaded
5970 // reference, if heap poisoning is enabled).
5971 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
5972 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005973 Register temp = IP;
5974
5975 if (has_intermediate_address) {
5976 // We do not need to compute the intermediate address from the array: the
5977 // input instruction has done it already. See the comment in
5978 // `TryExtractArrayAccessAddress()`.
5979 if (kIsDebugBuild) {
5980 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5981 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5982 }
5983 temp = obj;
5984 } else {
5985 __ add(temp, obj, ShifterOperand(data_offset));
5986 }
5987 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Artem Serov6c916792016-07-11 14:02:34 +01005988
Roland Levillainc9285912015-12-18 10:38:42 +00005989 codegen_->MaybeRecordImplicitNullCheck(instruction);
5990 // If read barriers are enabled, emit read barriers other than
5991 // Baker's using a slow path (and also unpoison the loaded
5992 // reference, if heap poisoning is enabled).
5993 codegen_->MaybeGenerateReadBarrierSlow(
5994 instruction, out_loc, out_loc, obj_loc, data_offset, index);
5995 }
5996 }
5997 break;
5998 }
5999
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006000 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006001 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006002 size_t offset =
6003 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006004 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006005 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006006 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00006007 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006008 }
6009 break;
6010 }
6011
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006012 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00006013 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006014 if (index.IsConstant()) {
6015 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006016 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006017 } else {
6018 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00006019 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006020 }
6021 break;
6022 }
6023
6024 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00006025 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006026 if (index.IsConstant()) {
6027 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006028 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006029 } else {
6030 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00006031 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006032 }
6033 break;
6034 }
6035
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006036 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01006037 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07006038 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006039 }
Roland Levillain4d027112015-07-01 15:41:14 +01006040
6041 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00006042 // Potential implicit null checks, in the case of reference
6043 // arrays, are handled in the previous switch statement.
jessicahandojo05765752016-09-09 19:01:32 -07006044 } else if (!maybe_compressed_char_at) {
Roland Levillainc9285912015-12-18 10:38:42 +00006045 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01006046 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006047}
6048
6049void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01006050 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006051
6052 bool needs_write_barrier =
6053 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00006054 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006055
Nicolas Geoffray39468442014-09-02 15:17:15 +01006056 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006057 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01006058 may_need_runtime_call_for_type_check ?
Roland Levillain3b359c72015-11-17 19:35:12 +00006059 LocationSummary::kCallOnSlowPath :
6060 LocationSummary::kNoCall);
6061
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006062 locations->SetInAt(0, Location::RequiresRegister());
6063 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6064 if (Primitive::IsFloatingPointType(value_type)) {
6065 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006066 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006067 locations->SetInAt(2, Location::RequiresRegister());
6068 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006069 if (needs_write_barrier) {
6070 // Temporary registers for the write barrier.
6071 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00006072 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006073 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006074}
6075
6076void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
6077 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006078 Location array_loc = locations->InAt(0);
6079 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006080 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01006081 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00006082 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006083 bool needs_write_barrier =
6084 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Artem Serov6c916792016-07-11 14:02:34 +01006085 uint32_t data_offset =
6086 mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
6087 Location value_loc = locations->InAt(2);
Artem Serov328429f2016-07-06 16:23:04 +01006088 HInstruction* array_instr = instruction->GetArray();
6089 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006090
6091 switch (value_type) {
6092 case Primitive::kPrimBoolean:
Artem Serov6c916792016-07-11 14:02:34 +01006093 case Primitive::kPrimByte:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006094 case Primitive::kPrimShort:
Artem Serov6c916792016-07-11 14:02:34 +01006095 case Primitive::kPrimChar:
6096 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006097 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01006098 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
6099 uint32_t full_offset =
6100 data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
6101 StoreOperandType store_type = GetStoreOperandType(value_type);
6102 __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006103 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006104 Register temp = IP;
6105
6106 if (has_intermediate_address) {
6107 // We do not need to compute the intermediate address from the array: the
6108 // input instruction has done it already. See the comment in
6109 // `TryExtractArrayAccessAddress()`.
6110 if (kIsDebugBuild) {
6111 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6112 DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
6113 }
6114 temp = array;
6115 } else {
6116 __ add(temp, array, ShifterOperand(data_offset));
6117 }
Artem Serov6c916792016-07-11 14:02:34 +01006118 codegen_->StoreToShiftedRegOffset(value_type,
6119 value_loc,
Artem Serov328429f2016-07-06 16:23:04 +01006120 temp,
Artem Serov6c916792016-07-11 14:02:34 +01006121 index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006122 }
6123 break;
6124 }
6125
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006126 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00006127 Register value = value_loc.AsRegister<Register>();
Artem Serov328429f2016-07-06 16:23:04 +01006128 // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
6129 // See the comment in instruction_simplifier_shared.cc.
6130 DCHECK(!has_intermediate_address);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006131
6132 if (instruction->InputAt(2)->IsNullConstant()) {
6133 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006134 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006135 size_t offset =
6136 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Artem Serov6c916792016-07-11 14:02:34 +01006137 __ StoreToOffset(kStoreWord, value, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006138 } else {
6139 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006140 __ add(IP, array, ShifterOperand(data_offset));
6141 codegen_->StoreToShiftedRegOffset(value_type,
6142 value_loc,
6143 IP,
6144 index.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006145 }
Roland Levillain1407ee72016-01-08 15:56:19 +00006146 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00006147 DCHECK(!needs_write_barrier);
6148 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006149 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006150 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006151
6152 DCHECK(needs_write_barrier);
Roland Levillain16d9f942016-08-25 17:27:56 +01006153 Location temp1_loc = locations->GetTemp(0);
6154 Register temp1 = temp1_loc.AsRegister<Register>();
6155 Location temp2_loc = locations->GetTemp(1);
6156 Register temp2 = temp2_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006157 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6158 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6159 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6160 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006161 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01006162 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006163
Roland Levillain3b359c72015-11-17 19:35:12 +00006164 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006165 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
6166 codegen_->AddSlowPath(slow_path);
6167 if (instruction->GetValueCanBeNull()) {
6168 Label non_zero;
6169 __ CompareAndBranchIfNonZero(value, &non_zero);
6170 if (index.IsConstant()) {
6171 size_t offset =
6172 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6173 __ StoreToOffset(kStoreWord, value, array, offset);
6174 } else {
6175 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006176 __ add(IP, array, ShifterOperand(data_offset));
6177 codegen_->StoreToShiftedRegOffset(value_type,
6178 value_loc,
6179 IP,
6180 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006181 }
6182 codegen_->MaybeRecordImplicitNullCheck(instruction);
Anton Kirilov6f644202017-02-27 18:29:45 +00006183 __ b(final_label);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006184 __ Bind(&non_zero);
6185 }
6186
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006187 // Note that when read barriers are enabled, the type checks
6188 // are performed without read barriers. This is fine, even in
6189 // the case where a class object is in the from-space after
6190 // the flip, as a comparison involving such a type would not
6191 // produce a false positive; it may of course produce a false
6192 // negative, in which case we would take the ArraySet slow
6193 // path.
Roland Levillain16d9f942016-08-25 17:27:56 +01006194
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006195 // /* HeapReference<Class> */ temp1 = array->klass_
6196 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
6197 codegen_->MaybeRecordImplicitNullCheck(instruction);
6198 __ MaybeUnpoisonHeapReference(temp1);
Roland Levillain16d9f942016-08-25 17:27:56 +01006199
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006200 // /* HeapReference<Class> */ temp1 = temp1->component_type_
6201 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
6202 // /* HeapReference<Class> */ temp2 = value->klass_
6203 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
6204 // If heap poisoning is enabled, no need to unpoison `temp1`
6205 // nor `temp2`, as we are comparing two poisoned references.
6206 __ cmp(temp1, ShifterOperand(temp2));
Roland Levillain16d9f942016-08-25 17:27:56 +01006207
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006208 if (instruction->StaticTypeOfArrayIsObjectArray()) {
6209 Label do_put;
6210 __ b(&do_put, EQ);
6211 // If heap poisoning is enabled, the `temp1` reference has
6212 // not been unpoisoned yet; unpoison it now.
Roland Levillain3b359c72015-11-17 19:35:12 +00006213 __ MaybeUnpoisonHeapReference(temp1);
6214
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006215 // /* HeapReference<Class> */ temp1 = temp1->super_class_
6216 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
6217 // If heap poisoning is enabled, no need to unpoison
6218 // `temp1`, as we are comparing against null below.
6219 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
6220 __ Bind(&do_put);
6221 } else {
6222 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006223 }
6224 }
6225
Artem Serov6c916792016-07-11 14:02:34 +01006226 Register source = value;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006227 if (kPoisonHeapReferences) {
6228 // Note that in the case where `value` is a null reference,
6229 // we do not enter this block, as a null reference does not
6230 // need poisoning.
6231 DCHECK_EQ(value_type, Primitive::kPrimNot);
6232 __ Mov(temp1, value);
6233 __ PoisonHeapReference(temp1);
6234 source = temp1;
6235 }
6236
6237 if (index.IsConstant()) {
6238 size_t offset =
6239 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6240 __ StoreToOffset(kStoreWord, source, array, offset);
6241 } else {
6242 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006243
6244 __ add(IP, array, ShifterOperand(data_offset));
6245 codegen_->StoreToShiftedRegOffset(value_type,
6246 Location::RegisterLocation(source),
6247 IP,
6248 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006249 }
6250
Roland Levillain3b359c72015-11-17 19:35:12 +00006251 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006252 codegen_->MaybeRecordImplicitNullCheck(instruction);
6253 }
6254
6255 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
6256
6257 if (done.IsLinked()) {
6258 __ Bind(&done);
6259 }
6260
6261 if (slow_path != nullptr) {
6262 __ Bind(slow_path->GetExitLabel());
6263 }
6264
6265 break;
6266 }
6267
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006268 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006269 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006270 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006271 size_t offset =
6272 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006273 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006274 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006275 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006276 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006277 }
6278 break;
6279 }
6280
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006281 case Primitive::kPrimFloat: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006282 Location value = locations->InAt(2);
6283 DCHECK(value.IsFpuRegister());
6284 if (index.IsConstant()) {
6285 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006286 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006287 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006288 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006289 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
6290 }
6291 break;
6292 }
6293
6294 case Primitive::kPrimDouble: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006295 Location value = locations->InAt(2);
6296 DCHECK(value.IsFpuRegisterPair());
6297 if (index.IsConstant()) {
6298 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006299 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006300 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006301 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006302 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
6303 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006304
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006305 break;
6306 }
6307
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006308 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006309 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07006310 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006311 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006312
Roland Levillain80e67092016-01-08 16:04:55 +00006313 // Objects are handled in the switch.
6314 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00006315 codegen_->MaybeRecordImplicitNullCheck(instruction);
6316 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006317}
6318
6319void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01006320 LocationSummary* locations =
6321 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006322 locations->SetInAt(0, Location::RequiresRegister());
6323 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006324}
6325
6326void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
6327 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01006328 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00006329 Register obj = locations->InAt(0).AsRegister<Register>();
6330 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006331 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00006332 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo05765752016-09-09 19:01:32 -07006333 // Mask out compression flag from String's array length.
6334 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006335 __ Lsr(out, out, 1u);
jessicahandojo05765752016-09-09 19:01:32 -07006336 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006337}
6338
Artem Serov328429f2016-07-06 16:23:04 +01006339void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
Artem Serov328429f2016-07-06 16:23:04 +01006340 LocationSummary* locations =
6341 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6342
6343 locations->SetInAt(0, Location::RequiresRegister());
6344 locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
6345 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6346}
6347
6348void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
6349 LocationSummary* locations = instruction->GetLocations();
6350 Location out = locations->Out();
6351 Location first = locations->InAt(0);
6352 Location second = locations->InAt(1);
6353
Artem Serov328429f2016-07-06 16:23:04 +01006354 if (second.IsRegister()) {
6355 __ add(out.AsRegister<Register>(),
6356 first.AsRegister<Register>(),
6357 ShifterOperand(second.AsRegister<Register>()));
6358 } else {
6359 __ AddConstant(out.AsRegister<Register>(),
6360 first.AsRegister<Register>(),
6361 second.GetConstant()->AsIntConstant()->GetValue());
6362 }
6363}
6364
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006365void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006366 RegisterSet caller_saves = RegisterSet::Empty();
6367 InvokeRuntimeCallingConvention calling_convention;
6368 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6369 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
6370 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Artem Serov2dd053d2017-03-08 14:54:06 +00006371
6372 HInstruction* index = instruction->InputAt(0);
6373 HInstruction* length = instruction->InputAt(1);
6374 // If both index and length are constants we can statically check the bounds. But if at least one
6375 // of them is not encodable ArmEncodableConstantOrRegister will create
6376 // Location::RequiresRegister() which is not desired to happen. Instead we create constant
6377 // locations.
6378 bool both_const = index->IsConstant() && length->IsConstant();
6379 locations->SetInAt(0, both_const
6380 ? Location::ConstantLocation(index->AsConstant())
6381 : ArmEncodableConstantOrRegister(index, CMP));
6382 locations->SetInAt(1, both_const
6383 ? Location::ConstantLocation(length->AsConstant())
6384 : ArmEncodableConstantOrRegister(length, CMP));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006385}
6386
6387void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
6388 LocationSummary* locations = instruction->GetLocations();
Artem Serov2dd053d2017-03-08 14:54:06 +00006389 Location index_loc = locations->InAt(0);
6390 Location length_loc = locations->InAt(1);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006391
Artem Serov2dd053d2017-03-08 14:54:06 +00006392 if (length_loc.IsConstant()) {
6393 int32_t length = helpers::Int32ConstantFrom(length_loc);
6394 if (index_loc.IsConstant()) {
6395 // BCE will remove the bounds check if we are guaranteed to pass.
6396 int32_t index = helpers::Int32ConstantFrom(index_loc);
6397 if (index < 0 || index >= length) {
6398 SlowPathCodeARM* slow_path =
6399 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6400 codegen_->AddSlowPath(slow_path);
6401 __ b(slow_path->GetEntryLabel());
6402 } else {
6403 // Some optimization after BCE may have generated this, and we should not
6404 // generate a bounds check if it is a valid range.
6405 }
6406 return;
6407 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006408
Artem Serov2dd053d2017-03-08 14:54:06 +00006409 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6410 __ cmp(index_loc.AsRegister<Register>(), ShifterOperand(length));
6411 codegen_->AddSlowPath(slow_path);
6412 __ b(slow_path->GetEntryLabel(), HS);
6413 } else {
6414 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6415 if (index_loc.IsConstant()) {
6416 int32_t index = helpers::Int32ConstantFrom(index_loc);
6417 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index));
6418 } else {
6419 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index_loc.AsRegister<Register>()));
6420 }
6421 codegen_->AddSlowPath(slow_path);
6422 __ b(slow_path->GetEntryLabel(), LS);
6423 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006424}
6425
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006426void CodeGeneratorARM::MarkGCCard(Register temp,
6427 Register card,
6428 Register object,
6429 Register value,
6430 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00006431 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006432 if (can_be_null) {
6433 __ CompareAndBranchIfZero(value, &is_null);
6434 }
Andreas Gampe542451c2016-07-26 09:02:02 -07006435 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006436 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
6437 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006438 if (can_be_null) {
6439 __ Bind(&is_null);
6440 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006441}
6442
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006443void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006444 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006445}
6446
6447void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006448 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6449}
6450
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006451void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01006452 LocationSummary* locations =
6453 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01006454 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006455}
6456
6457void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006458 HBasicBlock* block = instruction->GetBlock();
6459 if (block->GetLoopInformation() != nullptr) {
6460 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6461 // The back edge will generate the suspend check.
6462 return;
6463 }
6464 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6465 // The goto will generate the suspend check.
6466 return;
6467 }
6468 GenerateSuspendCheck(instruction, nullptr);
6469}
6470
6471void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
6472 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006473 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01006474 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
6475 if (slow_path == nullptr) {
6476 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
6477 instruction->SetSlowPath(slow_path);
6478 codegen_->AddSlowPath(slow_path);
6479 if (successor != nullptr) {
6480 DCHECK(successor->IsLoopHeader());
6481 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
6482 }
6483 } else {
6484 DCHECK_EQ(slow_path->GetSuccessor(), successor);
6485 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006486
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00006487 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07006488 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006489 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006490 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006491 __ Bind(slow_path->GetReturnLabel());
6492 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006493 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006494 __ b(slow_path->GetEntryLabel());
6495 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006496}
6497
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006498ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
6499 return codegen_->GetAssembler();
6500}
6501
6502void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006503 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006504 Location source = move->GetSource();
6505 Location destination = move->GetDestination();
6506
6507 if (source.IsRegister()) {
6508 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006509 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006510 } else if (destination.IsFpuRegister()) {
6511 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006512 } else {
6513 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006514 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006515 SP, destination.GetStackIndex());
6516 }
6517 } else if (source.IsStackSlot()) {
6518 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006519 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006520 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006521 } else if (destination.IsFpuRegister()) {
6522 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006523 } else {
6524 DCHECK(destination.IsStackSlot());
6525 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
6526 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6527 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006528 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006529 if (destination.IsRegister()) {
6530 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
6531 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006532 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006533 } else {
6534 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006535 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
6536 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006537 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006538 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006539 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
6540 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006541 } else if (destination.IsRegisterPair()) {
6542 DCHECK(ExpectedPairLayout(destination));
6543 __ LoadFromOffset(
6544 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
6545 } else {
6546 DCHECK(destination.IsFpuRegisterPair()) << destination;
6547 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6548 SP,
6549 source.GetStackIndex());
6550 }
6551 } else if (source.IsRegisterPair()) {
6552 if (destination.IsRegisterPair()) {
6553 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
6554 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006555 } else if (destination.IsFpuRegisterPair()) {
6556 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6557 source.AsRegisterPairLow<Register>(),
6558 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006559 } else {
6560 DCHECK(destination.IsDoubleStackSlot()) << destination;
6561 DCHECK(ExpectedPairLayout(source));
6562 __ StoreToOffset(
6563 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
6564 }
6565 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006566 if (destination.IsRegisterPair()) {
6567 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6568 destination.AsRegisterPairHigh<Register>(),
6569 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6570 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006571 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6572 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6573 } else {
6574 DCHECK(destination.IsDoubleStackSlot()) << destination;
6575 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
6576 SP,
6577 destination.GetStackIndex());
6578 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006579 } else {
6580 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00006581 HConstant* constant = source.GetConstant();
6582 if (constant->IsIntConstant() || constant->IsNullConstant()) {
6583 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006584 if (destination.IsRegister()) {
6585 __ LoadImmediate(destination.AsRegister<Register>(), value);
6586 } else {
6587 DCHECK(destination.IsStackSlot());
6588 __ LoadImmediate(IP, value);
6589 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6590 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006591 } else if (constant->IsLongConstant()) {
6592 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006593 if (destination.IsRegisterPair()) {
6594 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
6595 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006596 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006597 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006598 __ LoadImmediate(IP, Low32Bits(value));
6599 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6600 __ LoadImmediate(IP, High32Bits(value));
6601 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6602 }
6603 } else if (constant->IsDoubleConstant()) {
6604 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006605 if (destination.IsFpuRegisterPair()) {
6606 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006607 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006608 DCHECK(destination.IsDoubleStackSlot()) << destination;
6609 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006610 __ LoadImmediate(IP, Low32Bits(int_value));
6611 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6612 __ LoadImmediate(IP, High32Bits(int_value));
6613 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6614 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006615 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006616 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006617 float value = constant->AsFloatConstant()->GetValue();
6618 if (destination.IsFpuRegister()) {
6619 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
6620 } else {
6621 DCHECK(destination.IsStackSlot());
6622 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
6623 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6624 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006625 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006626 }
6627}
6628
6629void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
6630 __ Mov(IP, reg);
6631 __ LoadFromOffset(kLoadWord, reg, SP, mem);
6632 __ StoreToOffset(kStoreWord, IP, SP, mem);
6633}
6634
6635void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
6636 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
6637 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
6638 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
6639 SP, mem1 + stack_offset);
6640 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
6641 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
6642 SP, mem2 + stack_offset);
6643 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
6644}
6645
6646void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006647 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006648 Location source = move->GetSource();
6649 Location destination = move->GetDestination();
6650
6651 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006652 DCHECK_NE(source.AsRegister<Register>(), IP);
6653 DCHECK_NE(destination.AsRegister<Register>(), IP);
6654 __ Mov(IP, source.AsRegister<Register>());
6655 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
6656 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006657 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006658 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006659 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006660 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006661 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
6662 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006663 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006664 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006665 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006666 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006667 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006668 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006669 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006670 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006671 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6672 destination.AsRegisterPairHigh<Register>(),
6673 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006674 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006675 Register low_reg = source.IsRegisterPair()
6676 ? source.AsRegisterPairLow<Register>()
6677 : destination.AsRegisterPairLow<Register>();
6678 int mem = source.IsRegisterPair()
6679 ? destination.GetStackIndex()
6680 : source.GetStackIndex();
6681 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006682 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006683 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006684 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006685 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006686 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
6687 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006688 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006689 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006690 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006691 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
6692 DRegister reg = source.IsFpuRegisterPair()
6693 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
6694 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
6695 int mem = source.IsFpuRegisterPair()
6696 ? destination.GetStackIndex()
6697 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006698 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006699 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006700 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006701 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
6702 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
6703 : destination.AsFpuRegister<SRegister>();
6704 int mem = source.IsFpuRegister()
6705 ? destination.GetStackIndex()
6706 : source.GetStackIndex();
6707
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006708 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006709 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006710 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006711 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006712 Exchange(source.GetStackIndex(), destination.GetStackIndex());
6713 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006714 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006715 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006716 }
6717}
6718
6719void ParallelMoveResolverARM::SpillScratch(int reg) {
6720 __ Push(static_cast<Register>(reg));
6721}
6722
6723void ParallelMoveResolverARM::RestoreScratch(int reg) {
6724 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006725}
6726
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006727HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
6728 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006729 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00006730 case HLoadClass::LoadKind::kInvalid:
6731 LOG(FATAL) << "UNREACHABLE";
6732 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006733 case HLoadClass::LoadKind::kReferrersClass:
6734 break;
6735 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
6736 DCHECK(!GetCompilerOptions().GetCompilePic());
6737 break;
6738 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
6739 DCHECK(GetCompilerOptions().GetCompilePic());
6740 break;
6741 case HLoadClass::LoadKind::kBootImageAddress:
6742 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006743 case HLoadClass::LoadKind::kBssEntry:
6744 DCHECK(!Runtime::Current()->UseJitCompilation());
6745 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006746 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006747 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006748 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006749 case HLoadClass::LoadKind::kDexCacheViaMethod:
6750 break;
6751 }
6752 return desired_class_load_kind;
6753}
6754
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006755void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00006756 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
6757 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006758 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00006759 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006760 cls,
6761 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00006762 Location::RegisterLocation(R0));
Vladimir Markoea4c1262017-02-06 19:59:33 +00006763 DCHECK_EQ(calling_convention.GetRegisterAt(0), R0);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006764 return;
6765 }
Vladimir Marko41559982017-01-06 14:04:23 +00006766 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006767
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006768 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
6769 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006770 ? LocationSummary::kCallOnSlowPath
6771 : LocationSummary::kNoCall;
6772 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006773 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006774 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006775 }
6776
Vladimir Marko41559982017-01-06 14:04:23 +00006777 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006778 locations->SetInAt(0, Location::RequiresRegister());
6779 }
6780 locations->SetOut(Location::RequiresRegister());
Vladimir Markoea4c1262017-02-06 19:59:33 +00006781 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
6782 if (!kUseReadBarrier || kUseBakerReadBarrier) {
6783 // Rely on the type resolution or initialization and marking to save everything we need.
6784 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
6785 // to the custom calling convention) or by marking, so we request a different temp.
6786 locations->AddTemp(Location::RequiresRegister());
6787 RegisterSet caller_saves = RegisterSet::Empty();
6788 InvokeRuntimeCallingConvention calling_convention;
6789 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6790 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
6791 // that the the kPrimNot result register is the same as the first argument register.
6792 locations->SetCustomSlowPathCallerSaves(caller_saves);
6793 } else {
6794 // For non-Baker read barrier we have a temp-clobbering call.
6795 }
6796 }
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01006797 if (kUseBakerReadBarrier && kBakerReadBarrierLinkTimeThunksEnableForGcRoots) {
6798 if (load_kind == HLoadClass::LoadKind::kBssEntry ||
6799 (load_kind == HLoadClass::LoadKind::kReferrersClass &&
6800 !Runtime::Current()->UseJitCompilation())) {
6801 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
6802 }
6803 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006804}
6805
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006806// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6807// move.
6808void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00006809 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
6810 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
6811 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01006812 return;
6813 }
Vladimir Marko41559982017-01-06 14:04:23 +00006814 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01006815
Vladimir Marko41559982017-01-06 14:04:23 +00006816 LocationSummary* locations = cls->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006817 Location out_loc = locations->Out();
6818 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00006819
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006820 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
6821 ? kWithoutReadBarrier
6822 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006823 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00006824 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006825 case HLoadClass::LoadKind::kReferrersClass: {
6826 DCHECK(!cls->CanCallRuntime());
6827 DCHECK(!cls->MustGenerateClinitCheck());
6828 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
6829 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006830 GenerateGcRootFieldLoad(cls,
6831 out_loc,
6832 current_method,
6833 ArtMethod::DeclaringClassOffset().Int32Value(),
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006834 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006835 break;
6836 }
6837 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006838 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006839 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006840 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
6841 cls->GetTypeIndex()));
6842 break;
6843 }
6844 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006845 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006846 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006847 CodeGeneratorARM::PcRelativePatchInfo* labels =
6848 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
6849 __ BindTrackedLabel(&labels->movw_label);
6850 __ movw(out, /* placeholder */ 0u);
6851 __ BindTrackedLabel(&labels->movt_label);
6852 __ movt(out, /* placeholder */ 0u);
6853 __ BindTrackedLabel(&labels->add_pc_label);
6854 __ add(out, out, ShifterOperand(PC));
6855 break;
6856 }
6857 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006858 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006859 uint32_t address = dchecked_integral_cast<uint32_t>(
6860 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
6861 DCHECK_NE(address, 0u);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006862 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
6863 break;
6864 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006865 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Markoea4c1262017-02-06 19:59:33 +00006866 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
6867 ? locations->GetTemp(0).AsRegister<Register>()
6868 : out;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006869 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko1998cd02017-01-13 13:02:58 +00006870 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006871 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00006872 __ movw(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006873 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00006874 __ movt(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006875 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00006876 __ add(temp, temp, ShifterOperand(PC));
6877 GenerateGcRootFieldLoad(cls, out_loc, temp, /* offset */ 0, read_barrier_option);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006878 generate_null_check = true;
6879 break;
6880 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006881 case HLoadClass::LoadKind::kJitTableAddress: {
6882 __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
6883 cls->GetTypeIndex(),
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006884 cls->GetClass()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006885 // /* GcRoot<mirror::Class> */ out = *out
Vladimir Markoea4c1262017-02-06 19:59:33 +00006886 GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006887 break;
6888 }
Vladimir Marko41559982017-01-06 14:04:23 +00006889 case HLoadClass::LoadKind::kDexCacheViaMethod:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00006890 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00006891 LOG(FATAL) << "UNREACHABLE";
6892 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006893 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006894
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006895 if (generate_null_check || cls->MustGenerateClinitCheck()) {
6896 DCHECK(cls->CanCallRuntime());
Artem Serovf4d6aee2016-07-11 10:41:45 +01006897 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006898 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
6899 codegen_->AddSlowPath(slow_path);
6900 if (generate_null_check) {
6901 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
6902 }
6903 if (cls->MustGenerateClinitCheck()) {
6904 GenerateClassInitializationCheck(slow_path, out);
6905 } else {
6906 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006907 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006908 }
6909}
6910
6911void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
6912 LocationSummary* locations =
6913 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
6914 locations->SetInAt(0, Location::RequiresRegister());
6915 if (check->HasUses()) {
6916 locations->SetOut(Location::SameAsFirstInput());
6917 }
6918}
6919
6920void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006921 // We assume the class is not null.
Artem Serovf4d6aee2016-07-11 10:41:45 +01006922 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006923 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006924 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00006925 GenerateClassInitializationCheck(slow_path,
6926 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006927}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006928
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006929void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Artem Serovf4d6aee2016-07-11 10:41:45 +01006930 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006931 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
6932 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
6933 __ b(slow_path->GetEntryLabel(), LT);
6934 // Even if the initialized flag is set, we may be in a situation where caches are not synced
6935 // properly. Therefore, we do a memory fence.
6936 __ dmb(ISH);
6937 __ Bind(slow_path->GetExitLabel());
6938}
6939
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006940HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
6941 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006942 switch (desired_string_load_kind) {
6943 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
6944 DCHECK(!GetCompilerOptions().GetCompilePic());
6945 break;
6946 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
6947 DCHECK(GetCompilerOptions().GetCompilePic());
6948 break;
6949 case HLoadString::LoadKind::kBootImageAddress:
6950 break;
Vladimir Markoaad75c62016-10-03 08:46:48 +00006951 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01006952 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006953 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006954 case HLoadString::LoadKind::kJitTableAddress:
6955 DCHECK(Runtime::Current()->UseJitCompilation());
6956 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006957 case HLoadString::LoadKind::kDexCacheViaMethod:
6958 break;
6959 }
6960 return desired_string_load_kind;
6961}
6962
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006963void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006964 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00006965 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006966 HLoadString::LoadKind load_kind = load->GetLoadKind();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006967 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006968 locations->SetOut(Location::RegisterLocation(R0));
6969 } else {
6970 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006971 if (load_kind == HLoadString::LoadKind::kBssEntry) {
6972 if (!kUseReadBarrier || kUseBakerReadBarrier) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00006973 // Rely on the pResolveString and marking to save everything we need, including temps.
6974 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
6975 // to the custom calling convention) or by marking, so we request a different temp.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006976 locations->AddTemp(Location::RequiresRegister());
6977 RegisterSet caller_saves = RegisterSet::Empty();
6978 InvokeRuntimeCallingConvention calling_convention;
6979 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6980 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
6981 // that the the kPrimNot result register is the same as the first argument register.
6982 locations->SetCustomSlowPathCallerSaves(caller_saves);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01006983 if (kUseBakerReadBarrier && kBakerReadBarrierLinkTimeThunksEnableForGcRoots) {
6984 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
6985 }
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006986 } else {
6987 // For non-Baker read barrier we have a temp-clobbering call.
6988 }
6989 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006990 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006991}
6992
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006993// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6994// move.
6995void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01006996 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006997 Location out_loc = locations->Out();
6998 Register out = out_loc.AsRegister<Register>();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006999 HLoadString::LoadKind load_kind = load->GetLoadKind();
Roland Levillain3b359c72015-11-17 19:35:12 +00007000
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007001 switch (load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007002 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007003 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007004 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
7005 load->GetStringIndex()));
7006 return; // No dex cache slow path.
7007 }
7008 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00007009 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007010 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007011 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007012 __ BindTrackedLabel(&labels->movw_label);
7013 __ movw(out, /* placeholder */ 0u);
7014 __ BindTrackedLabel(&labels->movt_label);
7015 __ movt(out, /* placeholder */ 0u);
7016 __ BindTrackedLabel(&labels->add_pc_label);
7017 __ add(out, out, ShifterOperand(PC));
7018 return; // No dex cache slow path.
7019 }
7020 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007021 uint32_t address = dchecked_integral_cast<uint32_t>(
7022 reinterpret_cast<uintptr_t>(load->GetString().Get()));
7023 DCHECK_NE(address, 0u);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007024 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
7025 return; // No dex cache slow path.
7026 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00007027 case HLoadString::LoadKind::kBssEntry: {
7028 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markoea4c1262017-02-06 19:59:33 +00007029 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
7030 ? locations->GetTemp(0).AsRegister<Register>()
7031 : out;
Vladimir Markoaad75c62016-10-03 08:46:48 +00007032 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007033 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markoaad75c62016-10-03 08:46:48 +00007034 __ BindTrackedLabel(&labels->movw_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007035 __ movw(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007036 __ BindTrackedLabel(&labels->movt_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007037 __ movt(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007038 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007039 __ add(temp, temp, ShifterOperand(PC));
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007040 GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007041 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
7042 codegen_->AddSlowPath(slow_path);
7043 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
7044 __ Bind(slow_path->GetExitLabel());
7045 return;
7046 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007047 case HLoadString::LoadKind::kJitTableAddress: {
7048 __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007049 load->GetStringIndex(),
7050 load->GetString()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007051 // /* GcRoot<mirror::String> */ out = *out
7052 GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
7053 return;
7054 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007055 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07007056 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007057 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007058
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007059 // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
7060 DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
7061 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007062 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007063 __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007064 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
7065 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007066}
7067
David Brazdilcb1c0552015-08-04 16:22:25 +01007068static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07007069 return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
David Brazdilcb1c0552015-08-04 16:22:25 +01007070}
7071
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007072void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
7073 LocationSummary* locations =
7074 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
7075 locations->SetOut(Location::RequiresRegister());
7076}
7077
7078void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00007079 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01007080 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
7081}
7082
7083void LocationsBuilderARM::VisitClearException(HClearException* clear) {
7084 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
7085}
7086
7087void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007088 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01007089 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007090}
7091
7092void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
7093 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01007094 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007095 InvokeRuntimeCallingConvention calling_convention;
7096 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7097}
7098
7099void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01007100 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007101 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007102}
7103
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007104// Temp is used for read barrier.
7105static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
7106 if (kEmitCompilerReadBarrier &&
7107 (kUseBakerReadBarrier ||
7108 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7109 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7110 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
7111 return 1;
7112 }
7113 return 0;
7114}
7115
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007116// Interface case has 3 temps, one for holding the number of interfaces, one for the current
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007117// interface pointer, one for loading the current interface.
7118// The other checks have one temp for loading the object's class.
7119static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
7120 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7121 return 3;
7122 }
7123 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Roland Levillainc9285912015-12-18 10:38:42 +00007124}
7125
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007126void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007127 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00007128 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01007129 bool baker_read_barrier_slow_path = false;
Roland Levillain3b359c72015-11-17 19:35:12 +00007130 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007131 case TypeCheckKind::kExactCheck:
7132 case TypeCheckKind::kAbstractClassCheck:
7133 case TypeCheckKind::kClassHierarchyCheck:
7134 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007135 call_kind =
7136 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01007137 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007138 break;
7139 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007140 case TypeCheckKind::kUnresolvedCheck:
7141 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007142 call_kind = LocationSummary::kCallOnSlowPath;
7143 break;
7144 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007145
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007146 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01007147 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007148 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007149 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007150 locations->SetInAt(0, Location::RequiresRegister());
7151 locations->SetInAt(1, Location::RequiresRegister());
7152 // The "out" register is used as a temporary, so it overlaps with the inputs.
7153 // Note that TypeCheckSlowPathARM uses this register too.
7154 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007155 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01007156 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
7157 codegen_->MaybeAddBakerCcEntrypointTempForFields(locations);
7158 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007159}
7160
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007161void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007162 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007163 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007164 Location obj_loc = locations->InAt(0);
7165 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007166 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007167 Location out_loc = locations->Out();
7168 Register out = out_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007169 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7170 DCHECK_LE(num_temps, 1u);
7171 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007172 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007173 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7174 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7175 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007176 Label done;
7177 Label* const final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01007178 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007179
7180 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007181 // avoid null check if we know obj is not null.
7182 if (instruction->MustDoNullCheck()) {
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007183 DCHECK_NE(out, obj);
7184 __ LoadImmediate(out, 0);
7185 __ CompareAndBranchIfZero(obj, final_label);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007186 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007187
Roland Levillainc9285912015-12-18 10:38:42 +00007188 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007189 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007190 // /* HeapReference<Class> */ out = obj->klass_
7191 GenerateReferenceLoadTwoRegisters(instruction,
7192 out_loc,
7193 obj_loc,
7194 class_offset,
7195 maybe_temp_loc,
7196 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007197 // Classes must be equal for the instanceof to succeed.
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007198 __ cmp(out, ShifterOperand(cls));
7199 // We speculatively set the result to false without changing the condition
7200 // flags, which allows us to avoid some branching later.
7201 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7202
7203 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7204 // we check that the output is in a low register, so that a 16-bit MOV
7205 // encoding can be used.
7206 if (ArmAssembler::IsLowRegister(out)) {
7207 __ it(EQ);
7208 __ mov(out, ShifterOperand(1), EQ);
7209 } else {
7210 __ b(final_label, NE);
7211 __ LoadImmediate(out, 1);
7212 }
7213
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007214 break;
7215 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007216
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007217 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007218 // /* HeapReference<Class> */ out = obj->klass_
7219 GenerateReferenceLoadTwoRegisters(instruction,
7220 out_loc,
7221 obj_loc,
7222 class_offset,
7223 maybe_temp_loc,
7224 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007225 // If the class is abstract, we eagerly fetch the super class of the
7226 // object to avoid doing a comparison we know will fail.
7227 Label loop;
7228 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007229 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007230 GenerateReferenceLoadOneRegister(instruction,
7231 out_loc,
7232 super_offset,
7233 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007234 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007235 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007236 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007237 __ cmp(out, ShifterOperand(cls));
7238 __ b(&loop, NE);
7239 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007240 break;
7241 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007242
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007243 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007244 // /* HeapReference<Class> */ out = obj->klass_
7245 GenerateReferenceLoadTwoRegisters(instruction,
7246 out_loc,
7247 obj_loc,
7248 class_offset,
7249 maybe_temp_loc,
7250 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007251 // Walk over the class hierarchy to find a match.
7252 Label loop, success;
7253 __ Bind(&loop);
7254 __ cmp(out, ShifterOperand(cls));
7255 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007256 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007257 GenerateReferenceLoadOneRegister(instruction,
7258 out_loc,
7259 super_offset,
7260 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007261 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007262 // This is essentially a null check, but it sets the condition flags to the
7263 // proper value for the code that follows the loop, i.e. not `EQ`.
7264 __ cmp(out, ShifterOperand(1));
7265 __ b(&loop, HS);
7266
7267 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7268 // we check that the output is in a low register, so that a 16-bit MOV
7269 // encoding can be used.
7270 if (ArmAssembler::IsLowRegister(out)) {
7271 // If `out` is null, we use it for the result, and the condition flags
7272 // have already been set to `NE`, so the IT block that comes afterwards
7273 // (and which handles the successful case) turns into a NOP (instead of
7274 // overwriting `out`).
7275 __ Bind(&success);
7276 // There is only one branch to the `success` label (which is bound to this
7277 // IT block), and it has the same condition, `EQ`, so in that case the MOV
7278 // is executed.
7279 __ it(EQ);
7280 __ mov(out, ShifterOperand(1), EQ);
7281 } else {
7282 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007283 __ b(final_label);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007284 __ Bind(&success);
7285 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007286 }
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007287
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007288 break;
7289 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007290
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007291 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007292 // /* HeapReference<Class> */ out = obj->klass_
7293 GenerateReferenceLoadTwoRegisters(instruction,
7294 out_loc,
7295 obj_loc,
7296 class_offset,
7297 maybe_temp_loc,
7298 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007299 // Do an exact check.
7300 Label exact_check;
7301 __ cmp(out, ShifterOperand(cls));
7302 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007303 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007304 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007305 GenerateReferenceLoadOneRegister(instruction,
7306 out_loc,
7307 component_offset,
7308 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007309 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007310 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007311 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007312 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
7313 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007314 __ cmp(out, ShifterOperand(0));
7315 // We speculatively set the result to false without changing the condition
7316 // flags, which allows us to avoid some branching later.
7317 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7318
7319 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7320 // we check that the output is in a low register, so that a 16-bit MOV
7321 // encoding can be used.
7322 if (ArmAssembler::IsLowRegister(out)) {
7323 __ Bind(&exact_check);
7324 __ it(EQ);
7325 __ mov(out, ShifterOperand(1), EQ);
7326 } else {
7327 __ b(final_label, NE);
7328 __ Bind(&exact_check);
7329 __ LoadImmediate(out, 1);
7330 }
7331
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007332 break;
7333 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007334
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007335 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007336 // No read barrier since the slow path will retry upon failure.
7337 // /* HeapReference<Class> */ out = obj->klass_
7338 GenerateReferenceLoadTwoRegisters(instruction,
7339 out_loc,
7340 obj_loc,
7341 class_offset,
7342 maybe_temp_loc,
7343 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007344 __ cmp(out, ShifterOperand(cls));
7345 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00007346 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7347 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007348 codegen_->AddSlowPath(slow_path);
7349 __ b(slow_path->GetEntryLabel(), NE);
7350 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007351 break;
7352 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007353
Calin Juravle98893e12015-10-02 21:05:03 +01007354 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007355 case TypeCheckKind::kInterfaceCheck: {
7356 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007357 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00007358 // cases.
7359 //
7360 // We cannot directly call the InstanceofNonTrivial runtime
7361 // entry point without resorting to a type checking slow path
7362 // here (i.e. by calling InvokeRuntime directly), as it would
7363 // require to assign fixed registers for the inputs of this
7364 // HInstanceOf instruction (following the runtime calling
7365 // convention), which might be cluttered by the potential first
7366 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00007367 //
7368 // TODO: Introduce a new runtime entry point taking the object
7369 // to test (instead of its class) as argument, and let it deal
7370 // with the read barrier issues. This will let us refactor this
7371 // case of the `switch` code as it was previously (with a direct
7372 // call to the runtime not using a type checking slow path).
7373 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00007374 DCHECK(locations->OnlyCallsOnSlowPath());
7375 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7376 /* is_fatal */ false);
7377 codegen_->AddSlowPath(slow_path);
7378 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007379 break;
7380 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007381 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007382
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007383 if (done.IsLinked()) {
7384 __ Bind(&done);
7385 }
7386
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007387 if (slow_path != nullptr) {
7388 __ Bind(slow_path->GetExitLabel());
7389 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007390}
7391
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007392void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007393 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7394 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
7395
Roland Levillain3b359c72015-11-17 19:35:12 +00007396 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7397 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007398 case TypeCheckKind::kExactCheck:
7399 case TypeCheckKind::kAbstractClassCheck:
7400 case TypeCheckKind::kClassHierarchyCheck:
7401 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007402 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
7403 LocationSummary::kCallOnSlowPath :
7404 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007405 break;
7406 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007407 case TypeCheckKind::kUnresolvedCheck:
7408 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007409 call_kind = LocationSummary::kCallOnSlowPath;
7410 break;
7411 }
7412
Roland Levillain3b359c72015-11-17 19:35:12 +00007413 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
7414 locations->SetInAt(0, Location::RequiresRegister());
7415 locations->SetInAt(1, Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007416 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007417}
7418
7419void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007420 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007421 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007422 Location obj_loc = locations->InAt(0);
7423 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007424 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007425 Location temp_loc = locations->GetTemp(0);
7426 Register temp = temp_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007427 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
7428 DCHECK_LE(num_temps, 3u);
7429 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
7430 Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
7431 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7432 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7433 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7434 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7435 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
7436 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
7437 const uint32_t object_array_data_offset =
7438 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007439
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007440 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
7441 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
7442 // read barriers is done for performance and code size reasons.
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007443 bool is_type_check_slow_path_fatal = false;
7444 if (!kEmitCompilerReadBarrier) {
7445 is_type_check_slow_path_fatal =
7446 (type_check_kind == TypeCheckKind::kExactCheck ||
7447 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7448 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7449 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
7450 !instruction->CanThrowIntoCatchBlock();
7451 }
Artem Serovf4d6aee2016-07-11 10:41:45 +01007452 SlowPathCodeARM* type_check_slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00007453 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7454 is_type_check_slow_path_fatal);
7455 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007456
7457 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00007458 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007459 // Avoid null check if we know obj is not null.
7460 if (instruction->MustDoNullCheck()) {
Anton Kirilov6f644202017-02-27 18:29:45 +00007461 __ CompareAndBranchIfZero(obj, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007462 }
7463
Roland Levillain3b359c72015-11-17 19:35:12 +00007464 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007465 case TypeCheckKind::kExactCheck:
7466 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007467 // /* HeapReference<Class> */ temp = obj->klass_
7468 GenerateReferenceLoadTwoRegisters(instruction,
7469 temp_loc,
7470 obj_loc,
7471 class_offset,
7472 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007473 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007474
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007475 __ cmp(temp, ShifterOperand(cls));
7476 // Jump to slow path for throwing the exception or doing a
7477 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00007478 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007479 break;
7480 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007481
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007482 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007483 // /* HeapReference<Class> */ temp = obj->klass_
7484 GenerateReferenceLoadTwoRegisters(instruction,
7485 temp_loc,
7486 obj_loc,
7487 class_offset,
7488 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007489 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007490
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007491 // If the class is abstract, we eagerly fetch the super class of the
7492 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007493 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007494 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007495 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007496 GenerateReferenceLoadOneRegister(instruction,
7497 temp_loc,
7498 super_offset,
7499 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007500 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007501
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007502 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7503 // exception.
7504 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
Roland Levillain3b359c72015-11-17 19:35:12 +00007505
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007506 // Otherwise, compare the classes.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007507 __ cmp(temp, ShifterOperand(cls));
7508 __ b(&loop, NE);
7509 break;
7510 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007511
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007512 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007513 // /* HeapReference<Class> */ temp = obj->klass_
7514 GenerateReferenceLoadTwoRegisters(instruction,
7515 temp_loc,
7516 obj_loc,
7517 class_offset,
7518 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007519 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007520
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007521 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007522 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007523 __ Bind(&loop);
7524 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007525 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007526
Roland Levillain3b359c72015-11-17 19:35:12 +00007527 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007528 GenerateReferenceLoadOneRegister(instruction,
7529 temp_loc,
7530 super_offset,
7531 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007532 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007533
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007534 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7535 // exception.
7536 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7537 // Otherwise, jump to the beginning of the loop.
7538 __ b(&loop);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007539 break;
7540 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007541
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007542 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007543 // /* HeapReference<Class> */ temp = obj->klass_
7544 GenerateReferenceLoadTwoRegisters(instruction,
7545 temp_loc,
7546 obj_loc,
7547 class_offset,
7548 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007549 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007550
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007551 // Do an exact check.
7552 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007553 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007554
7555 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007556 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007557 GenerateReferenceLoadOneRegister(instruction,
7558 temp_loc,
7559 component_offset,
7560 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007561 kWithoutReadBarrier);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007562 // If the component type is null, jump to the slow path to throw the exception.
7563 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7564 // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
7565 // to further check that this component type is not a primitive type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007566 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00007567 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007568 __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007569 break;
7570 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007571
Calin Juravle98893e12015-10-02 21:05:03 +01007572 case TypeCheckKind::kUnresolvedCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007573 // We always go into the type check slow path for the unresolved check case.
Roland Levillain3b359c72015-11-17 19:35:12 +00007574 // We cannot directly call the CheckCast runtime entry point
7575 // without resorting to a type checking slow path here (i.e. by
7576 // calling InvokeRuntime directly), as it would require to
7577 // assign fixed registers for the inputs of this HInstanceOf
7578 // instruction (following the runtime calling convention), which
7579 // might be cluttered by the potential first read barrier
7580 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007581
Roland Levillain3b359c72015-11-17 19:35:12 +00007582 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007583 break;
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007584
7585 case TypeCheckKind::kInterfaceCheck: {
7586 // Avoid read barriers to improve performance of the fast path. We can not get false
7587 // positives by doing this.
7588 // /* HeapReference<Class> */ temp = obj->klass_
7589 GenerateReferenceLoadTwoRegisters(instruction,
7590 temp_loc,
7591 obj_loc,
7592 class_offset,
7593 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007594 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007595
7596 // /* HeapReference<Class> */ temp = temp->iftable_
7597 GenerateReferenceLoadTwoRegisters(instruction,
7598 temp_loc,
7599 temp_loc,
7600 iftable_offset,
7601 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007602 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08007603 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007604 __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08007605 // Loop through the iftable and check if any class matches.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007606 Label start_loop;
7607 __ Bind(&start_loop);
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007608 __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
7609 type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007610 __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
7611 __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007612 // Go to next interface.
7613 __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
7614 __ sub(maybe_temp2_loc.AsRegister<Register>(),
7615 maybe_temp2_loc.AsRegister<Register>(),
7616 ShifterOperand(2));
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007617 // Compare the classes and continue the loop if they do not match.
7618 __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
7619 __ b(&start_loop, NE);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007620 break;
7621 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007622 }
Anton Kirilov6f644202017-02-27 18:29:45 +00007623
7624 if (done.IsLinked()) {
7625 __ Bind(&done);
7626 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007627
Roland Levillain3b359c72015-11-17 19:35:12 +00007628 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007629}
7630
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007631void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
7632 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01007633 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007634 InvokeRuntimeCallingConvention calling_convention;
7635 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7636}
7637
7638void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01007639 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
7640 instruction,
7641 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007642 if (instruction->IsEnter()) {
7643 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
7644 } else {
7645 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
7646 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007647}
7648
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007649void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
7650void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
7651void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007652
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007653void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007654 LocationSummary* locations =
7655 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7656 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7657 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007658 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007659 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007660 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00007661 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007662}
7663
7664void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
7665 HandleBitwiseOperation(instruction);
7666}
7667
7668void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
7669 HandleBitwiseOperation(instruction);
7670}
7671
7672void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
7673 HandleBitwiseOperation(instruction);
7674}
7675
Artem Serov7fc63502016-02-09 17:15:29 +00007676
7677void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7678 LocationSummary* locations =
7679 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7680 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7681 || instruction->GetResultType() == Primitive::kPrimLong);
7682
7683 locations->SetInAt(0, Location::RequiresRegister());
7684 locations->SetInAt(1, Location::RequiresRegister());
7685 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7686}
7687
7688void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7689 LocationSummary* locations = instruction->GetLocations();
7690 Location first = locations->InAt(0);
7691 Location second = locations->InAt(1);
7692 Location out = locations->Out();
7693
7694 if (instruction->GetResultType() == Primitive::kPrimInt) {
7695 Register first_reg = first.AsRegister<Register>();
7696 ShifterOperand second_reg(second.AsRegister<Register>());
7697 Register out_reg = out.AsRegister<Register>();
7698
7699 switch (instruction->GetOpKind()) {
7700 case HInstruction::kAnd:
7701 __ bic(out_reg, first_reg, second_reg);
7702 break;
7703 case HInstruction::kOr:
7704 __ orn(out_reg, first_reg, second_reg);
7705 break;
7706 // There is no EON on arm.
7707 case HInstruction::kXor:
7708 default:
7709 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7710 UNREACHABLE();
7711 }
7712 return;
7713
7714 } else {
7715 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7716 Register first_low = first.AsRegisterPairLow<Register>();
7717 Register first_high = first.AsRegisterPairHigh<Register>();
7718 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
7719 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
7720 Register out_low = out.AsRegisterPairLow<Register>();
7721 Register out_high = out.AsRegisterPairHigh<Register>();
7722
7723 switch (instruction->GetOpKind()) {
7724 case HInstruction::kAnd:
7725 __ bic(out_low, first_low, second_low);
7726 __ bic(out_high, first_high, second_high);
7727 break;
7728 case HInstruction::kOr:
7729 __ orn(out_low, first_low, second_low);
7730 __ orn(out_high, first_high, second_high);
7731 break;
7732 // There is no EON on arm.
7733 case HInstruction::kXor:
7734 default:
7735 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7736 UNREACHABLE();
7737 }
7738 }
7739}
7740
Anton Kirilov74234da2017-01-13 14:42:47 +00007741void LocationsBuilderARM::VisitDataProcWithShifterOp(
7742 HDataProcWithShifterOp* instruction) {
7743 DCHECK(instruction->GetType() == Primitive::kPrimInt ||
7744 instruction->GetType() == Primitive::kPrimLong);
7745 LocationSummary* locations =
7746 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7747 const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
7748 HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
7749
7750 locations->SetInAt(0, Location::RequiresRegister());
7751 locations->SetInAt(1, Location::RequiresRegister());
7752 locations->SetOut(Location::RequiresRegister(),
7753 overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
7754}
7755
7756void InstructionCodeGeneratorARM::VisitDataProcWithShifterOp(
7757 HDataProcWithShifterOp* instruction) {
7758 const LocationSummary* const locations = instruction->GetLocations();
7759 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
7760 const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
7761 const Location left = locations->InAt(0);
7762 const Location right = locations->InAt(1);
7763 const Location out = locations->Out();
7764
7765 if (instruction->GetType() == Primitive::kPrimInt) {
7766 DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
7767
7768 const Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
7769 ? right.AsRegisterPairLow<Register>()
7770 : right.AsRegister<Register>();
7771
7772 GenerateDataProcInstruction(kind,
7773 out.AsRegister<Register>(),
7774 left.AsRegister<Register>(),
7775 ShifterOperand(second,
7776 ShiftFromOpKind(op_kind),
7777 instruction->GetShiftAmount()),
7778 codegen_);
7779 } else {
7780 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
7781
7782 if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
7783 const Register second = right.AsRegister<Register>();
7784
7785 DCHECK_NE(out.AsRegisterPairLow<Register>(), second);
7786 GenerateDataProc(kind,
7787 out,
7788 left,
7789 ShifterOperand(second),
7790 ShifterOperand(second, ASR, 31),
7791 codegen_);
7792 } else {
7793 GenerateLongDataProc(instruction, codegen_);
7794 }
7795 }
7796}
7797
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007798void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
7799 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
7800 if (value == 0xffffffffu) {
7801 if (out != first) {
7802 __ mov(out, ShifterOperand(first));
7803 }
7804 return;
7805 }
7806 if (value == 0u) {
7807 __ mov(out, ShifterOperand(0));
7808 return;
7809 }
7810 ShifterOperand so;
7811 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
7812 __ and_(out, first, so);
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00007813 } else if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007814 __ bic(out, first, ShifterOperand(~value));
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00007815 } else {
7816 DCHECK(IsPowerOfTwo(value + 1));
7817 __ ubfx(out, first, 0, WhichPowerOf2(value + 1));
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007818 }
7819}
7820
7821void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
7822 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
7823 if (value == 0u) {
7824 if (out != first) {
7825 __ mov(out, ShifterOperand(first));
7826 }
7827 return;
7828 }
7829 if (value == 0xffffffffu) {
7830 __ mvn(out, ShifterOperand(0));
7831 return;
7832 }
7833 ShifterOperand so;
7834 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
7835 __ orr(out, first, so);
7836 } else {
7837 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
7838 __ orn(out, first, ShifterOperand(~value));
7839 }
7840}
7841
7842void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
7843 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
7844 if (value == 0u) {
7845 if (out != first) {
7846 __ mov(out, ShifterOperand(first));
7847 }
7848 return;
7849 }
7850 __ eor(out, first, ShifterOperand(value));
7851}
7852
Vladimir Marko59751a72016-08-05 14:37:27 +01007853void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
7854 Location first,
7855 uint64_t value) {
7856 Register out_low = out.AsRegisterPairLow<Register>();
7857 Register out_high = out.AsRegisterPairHigh<Register>();
7858 Register first_low = first.AsRegisterPairLow<Register>();
7859 Register first_high = first.AsRegisterPairHigh<Register>();
7860 uint32_t value_low = Low32Bits(value);
7861 uint32_t value_high = High32Bits(value);
7862 if (value_low == 0u) {
7863 if (out_low != first_low) {
7864 __ mov(out_low, ShifterOperand(first_low));
7865 }
7866 __ AddConstant(out_high, first_high, value_high);
7867 return;
7868 }
7869 __ AddConstantSetFlags(out_low, first_low, value_low);
7870 ShifterOperand so;
7871 if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
7872 __ adc(out_high, first_high, so);
7873 } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
7874 __ sbc(out_high, first_high, so);
7875 } else {
7876 LOG(FATAL) << "Unexpected constant " << value_high;
7877 UNREACHABLE();
7878 }
7879}
7880
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007881void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
7882 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007883 Location first = locations->InAt(0);
7884 Location second = locations->InAt(1);
7885 Location out = locations->Out();
7886
7887 if (second.IsConstant()) {
7888 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
7889 uint32_t value_low = Low32Bits(value);
7890 if (instruction->GetResultType() == Primitive::kPrimInt) {
7891 Register first_reg = first.AsRegister<Register>();
7892 Register out_reg = out.AsRegister<Register>();
7893 if (instruction->IsAnd()) {
7894 GenerateAndConst(out_reg, first_reg, value_low);
7895 } else if (instruction->IsOr()) {
7896 GenerateOrrConst(out_reg, first_reg, value_low);
7897 } else {
7898 DCHECK(instruction->IsXor());
7899 GenerateEorConst(out_reg, first_reg, value_low);
7900 }
7901 } else {
7902 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7903 uint32_t value_high = High32Bits(value);
7904 Register first_low = first.AsRegisterPairLow<Register>();
7905 Register first_high = first.AsRegisterPairHigh<Register>();
7906 Register out_low = out.AsRegisterPairLow<Register>();
7907 Register out_high = out.AsRegisterPairHigh<Register>();
7908 if (instruction->IsAnd()) {
7909 GenerateAndConst(out_low, first_low, value_low);
7910 GenerateAndConst(out_high, first_high, value_high);
7911 } else if (instruction->IsOr()) {
7912 GenerateOrrConst(out_low, first_low, value_low);
7913 GenerateOrrConst(out_high, first_high, value_high);
7914 } else {
7915 DCHECK(instruction->IsXor());
7916 GenerateEorConst(out_low, first_low, value_low);
7917 GenerateEorConst(out_high, first_high, value_high);
7918 }
7919 }
7920 return;
7921 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007922
7923 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007924 Register first_reg = first.AsRegister<Register>();
7925 ShifterOperand second_reg(second.AsRegister<Register>());
7926 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007927 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007928 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007929 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007930 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007931 } else {
7932 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007933 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007934 }
7935 } else {
7936 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007937 Register first_low = first.AsRegisterPairLow<Register>();
7938 Register first_high = first.AsRegisterPairHigh<Register>();
7939 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
7940 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
7941 Register out_low = out.AsRegisterPairLow<Register>();
7942 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007943 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007944 __ and_(out_low, first_low, second_low);
7945 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007946 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007947 __ orr(out_low, first_low, second_low);
7948 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007949 } else {
7950 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007951 __ eor(out_low, first_low, second_low);
7952 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007953 }
7954 }
7955}
7956
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007957void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
7958 HInstruction* instruction,
7959 Location out,
7960 uint32_t offset,
7961 Location maybe_temp,
7962 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00007963 Register out_reg = out.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007964 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007965 CHECK(kEmitCompilerReadBarrier);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007966 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00007967 if (kUseBakerReadBarrier) {
7968 // Load with fast path based Baker's read barrier.
7969 // /* HeapReference<Object> */ out = *(out + offset)
7970 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007971 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00007972 } else {
7973 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007974 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00007975 // in the following move operation, as we will need it for the
7976 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007977 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00007978 // /* HeapReference<Object> */ out = *(out + offset)
7979 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007980 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00007981 }
7982 } else {
7983 // Plain load with no read barrier.
7984 // /* HeapReference<Object> */ out = *(out + offset)
7985 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
7986 __ MaybeUnpoisonHeapReference(out_reg);
7987 }
7988}
7989
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007990void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
7991 HInstruction* instruction,
7992 Location out,
7993 Location obj,
7994 uint32_t offset,
7995 Location maybe_temp,
7996 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00007997 Register out_reg = out.AsRegister<Register>();
7998 Register obj_reg = obj.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007999 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08008000 CHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00008001 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008002 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00008003 // Load with fast path based Baker's read barrier.
8004 // /* HeapReference<Object> */ out = *(obj + offset)
8005 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008006 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00008007 } else {
8008 // Load with slow path based read barrier.
8009 // /* HeapReference<Object> */ out = *(obj + offset)
8010 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
8011 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
8012 }
8013 } else {
8014 // Plain load with no read barrier.
8015 // /* HeapReference<Object> */ out = *(obj + offset)
8016 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
8017 __ MaybeUnpoisonHeapReference(out_reg);
8018 }
8019}
8020
8021void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
8022 Location root,
8023 Register obj,
Mathieu Chartier31b12e32016-09-02 17:11:57 -07008024 uint32_t offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008025 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00008026 Register root_reg = root.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008027 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07008028 DCHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00008029 if (kUseBakerReadBarrier) {
8030 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
Roland Levillainba650a42017-03-06 13:52:32 +00008031 // Baker's read barrier are used.
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008032 if (kBakerReadBarrierLinkTimeThunksEnableForGcRoots &&
8033 !Runtime::Current()->UseJitCompilation()) {
8034 // Note that we do not actually check the value of `GetIsGcMarking()`
8035 // to decide whether to mark the loaded GC root or not. Instead, we
8036 // load into `temp` (actually kBakerCcEntrypointRegister) the read
8037 // barrier mark introspection entrypoint. If `temp` is null, it means
8038 // that `GetIsGcMarking()` is false, and vice versa.
8039 //
8040 // We use link-time generated thunks for the slow path. That thunk
8041 // checks the reference and jumps to the entrypoint if needed.
8042 //
8043 // temp = Thread::Current()->pReadBarrierMarkIntrospection
8044 // lr = &return_address;
8045 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
8046 // if (temp != nullptr) {
8047 // goto gc_root_thunk<root_reg>(lr)
8048 // }
8049 // return_address:
Roland Levillainc9285912015-12-18 10:38:42 +00008050
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008051 CheckLastTempIsBakerCcEntrypointRegister(instruction);
8052 uint32_t custom_data =
8053 linker::Thumb2RelativePatcher::EncodeBakerReadBarrierGcRootData(root_reg);
8054 Label* bne_label = codegen_->NewBakerReadBarrierPatch(custom_data);
Roland Levillainba650a42017-03-06 13:52:32 +00008055
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008056 // entrypoint_reg =
8057 // Thread::Current()->pReadBarrierMarkReg12, i.e. pReadBarrierMarkIntrospection.
8058 DCHECK_EQ(IP, 12);
8059 const int32_t entry_point_offset =
8060 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(IP);
8061 __ LoadFromOffset(kLoadWord, kBakerCcEntrypointRegister, TR, entry_point_offset);
Roland Levillainba650a42017-03-06 13:52:32 +00008062
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008063 Label return_address;
8064 __ AdrCode(LR, &return_address);
8065 __ CmpConstant(kBakerCcEntrypointRegister, 0);
8066 static_assert(
8067 BAKER_MARK_INTROSPECTION_GC_ROOT_LDR_OFFSET == -8,
8068 "GC root LDR must be 2 32-bit instructions (8B) before the return address label.");
8069 // Currently the offset is always within range. If that changes,
8070 // we shall have to split the load the same way as for fields.
8071 DCHECK_LT(offset, kReferenceLoadMinFarOffset);
8072 ScopedForce32Bit force_32bit(down_cast<Thumb2Assembler*>(GetAssembler()));
8073 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8074 EmitPlaceholderBne(codegen_, bne_label);
8075 __ Bind(&return_address);
8076 } else {
8077 // Note that we do not actually check the value of
8078 // `GetIsGcMarking()` to decide whether to mark the loaded GC
8079 // root or not. Instead, we load into `temp` the read barrier
8080 // mark entry point corresponding to register `root`. If `temp`
8081 // is null, it means that `GetIsGcMarking()` is false, and vice
8082 // versa.
8083 //
8084 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8085 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
8086 // if (temp != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8087 // // Slow path.
8088 // root = temp(root); // root = ReadBarrier::Mark(root); // Runtime entry point call.
8089 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008090
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008091 // Slow path marking the GC root `root`. The entrypoint will already be loaded in `temp`.
8092 Location temp = Location::RegisterLocation(LR);
8093 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
8094 instruction, root, /* entrypoint */ temp);
8095 codegen_->AddSlowPath(slow_path);
8096
8097 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8098 const int32_t entry_point_offset =
8099 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
8100 // Loading the entrypoint does not require a load acquire since it is only changed when
8101 // threads are suspended or running a checkpoint.
8102 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
8103
8104 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
8105 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8106 static_assert(
8107 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
8108 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
8109 "have different sizes.");
8110 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
8111 "art::mirror::CompressedReference<mirror::Object> and int32_t "
8112 "have different sizes.");
8113
8114 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8115 // checking GetIsGcMarking.
8116 __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
8117 __ Bind(slow_path->GetExitLabel());
8118 }
Roland Levillainc9285912015-12-18 10:38:42 +00008119 } else {
8120 // GC root loaded through a slow path for read barriers other
8121 // than Baker's.
8122 // /* GcRoot<mirror::Object>* */ root = obj + offset
8123 __ AddConstant(root_reg, obj, offset);
8124 // /* mirror::Object* */ root = root->Read()
8125 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
8126 }
8127 } else {
8128 // Plain GC root load with no read barrier.
8129 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
8130 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8131 // Note that GC roots are not affected by heap poisoning, thus we
8132 // do not have to unpoison `root_reg` here.
8133 }
8134}
8135
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008136void CodeGeneratorARM::MaybeAddBakerCcEntrypointTempForFields(LocationSummary* locations) {
8137 DCHECK(kEmitCompilerReadBarrier);
8138 DCHECK(kUseBakerReadBarrier);
8139 if (kBakerReadBarrierLinkTimeThunksEnableForFields) {
8140 if (!Runtime::Current()->UseJitCompilation()) {
8141 locations->AddTemp(Location::RegisterLocation(kBakerCcEntrypointRegister));
8142 }
8143 }
8144}
8145
Roland Levillainc9285912015-12-18 10:38:42 +00008146void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
8147 Location ref,
8148 Register obj,
8149 uint32_t offset,
8150 Location temp,
8151 bool needs_null_check) {
8152 DCHECK(kEmitCompilerReadBarrier);
8153 DCHECK(kUseBakerReadBarrier);
8154
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008155 if (kBakerReadBarrierLinkTimeThunksEnableForFields &&
8156 !Runtime::Current()->UseJitCompilation()) {
8157 // Note that we do not actually check the value of `GetIsGcMarking()`
8158 // to decide whether to mark the loaded reference or not. Instead, we
8159 // load into `temp` (actually kBakerCcEntrypointRegister) the read
8160 // barrier mark introspection entrypoint. If `temp` is null, it means
8161 // that `GetIsGcMarking()` is false, and vice versa.
8162 //
8163 // We use link-time generated thunks for the slow path. That thunk checks
8164 // the holder and jumps to the entrypoint if needed. If the holder is not
8165 // gray, it creates a fake dependency and returns to the LDR instruction.
8166 //
8167 // temp = Thread::Current()->pReadBarrierMarkIntrospection
8168 // lr = &gray_return_address;
8169 // if (temp != nullptr) {
8170 // goto field_thunk<holder_reg, base_reg>(lr)
8171 // }
8172 // not_gray_return_address:
8173 // // Original reference load. If the offset is too large to fit
8174 // // into LDR, we use an adjusted base register here.
8175 // GcRoot<mirror::Object> reference = *(obj+offset);
8176 // gray_return_address:
8177
8178 DCHECK_ALIGNED(offset, sizeof(mirror::HeapReference<mirror::Object>));
8179 Register base = obj;
8180 if (offset >= kReferenceLoadMinFarOffset) {
8181 base = temp.AsRegister<Register>();
8182 DCHECK_NE(base, kBakerCcEntrypointRegister);
8183 static_assert(IsPowerOfTwo(kReferenceLoadMinFarOffset), "Expecting a power of 2.");
8184 __ AddConstant(base, obj, offset & ~(kReferenceLoadMinFarOffset - 1u));
8185 offset &= (kReferenceLoadMinFarOffset - 1u);
8186 }
8187 CheckLastTempIsBakerCcEntrypointRegister(instruction);
8188 uint32_t custom_data =
8189 linker::Thumb2RelativePatcher::EncodeBakerReadBarrierFieldData(base, obj);
8190 Label* bne_label = NewBakerReadBarrierPatch(custom_data);
8191
8192 // entrypoint_reg =
8193 // Thread::Current()->pReadBarrierMarkReg12, i.e. pReadBarrierMarkIntrospection.
8194 DCHECK_EQ(IP, 12);
8195 const int32_t entry_point_offset =
8196 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(IP);
8197 __ LoadFromOffset(kLoadWord, kBakerCcEntrypointRegister, TR, entry_point_offset);
8198
8199 Label return_address;
8200 __ AdrCode(LR, &return_address);
8201 __ CmpConstant(kBakerCcEntrypointRegister, 0);
8202 ScopedForce32Bit force_32bit(down_cast<Thumb2Assembler*>(GetAssembler()));
8203 EmitPlaceholderBne(this, bne_label);
8204 static_assert(BAKER_MARK_INTROSPECTION_FIELD_LDR_OFFSET == (kPoisonHeapReferences ? -8 : -4),
8205 "Field LDR must be 1 32-bit instruction (4B) before the return address label; "
8206 " 2 32-bit instructions (8B) for heap poisoning.");
8207 Register ref_reg = ref.AsRegister<Register>();
8208 DCHECK_LT(offset, kReferenceLoadMinFarOffset);
8209 __ LoadFromOffset(kLoadWord, ref_reg, base, offset);
8210 if (needs_null_check) {
8211 MaybeRecordImplicitNullCheck(instruction);
8212 }
8213 GetAssembler()->MaybeUnpoisonHeapReference(ref_reg);
8214 __ Bind(&return_address);
8215 return;
8216 }
8217
Roland Levillainc9285912015-12-18 10:38:42 +00008218 // /* HeapReference<Object> */ ref = *(obj + offset)
8219 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01008220 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00008221 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008222 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008223}
8224
8225void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
8226 Location ref,
8227 Register obj,
8228 uint32_t data_offset,
8229 Location index,
8230 Location temp,
8231 bool needs_null_check) {
8232 DCHECK(kEmitCompilerReadBarrier);
8233 DCHECK(kUseBakerReadBarrier);
8234
Roland Levillainbfea3352016-06-23 13:48:47 +01008235 static_assert(
8236 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
8237 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008238 ScaleFactor scale_factor = TIMES_4;
8239
8240 if (kBakerReadBarrierLinkTimeThunksEnableForArrays &&
8241 !Runtime::Current()->UseJitCompilation()) {
8242 // Note that we do not actually check the value of `GetIsGcMarking()`
8243 // to decide whether to mark the loaded reference or not. Instead, we
8244 // load into `temp` (actually kBakerCcEntrypointRegister) the read
8245 // barrier mark introspection entrypoint. If `temp` is null, it means
8246 // that `GetIsGcMarking()` is false, and vice versa.
8247 //
8248 // We use link-time generated thunks for the slow path. That thunk checks
8249 // the holder and jumps to the entrypoint if needed. If the holder is not
8250 // gray, it creates a fake dependency and returns to the LDR instruction.
8251 //
8252 // temp = Thread::Current()->pReadBarrierMarkIntrospection
8253 // lr = &gray_return_address;
8254 // if (temp != nullptr) {
8255 // goto field_thunk<holder_reg, base_reg>(lr)
8256 // }
8257 // not_gray_return_address:
8258 // // Original reference load. If the offset is too large to fit
8259 // // into LDR, we use an adjusted base register here.
8260 // GcRoot<mirror::Object> reference = data[index];
8261 // gray_return_address:
8262
8263 DCHECK(index.IsValid());
8264 Register index_reg = index.AsRegister<Register>();
8265 Register ref_reg = ref.AsRegister<Register>();
8266 Register data_reg = temp.AsRegister<Register>();
8267 DCHECK_NE(data_reg, kBakerCcEntrypointRegister);
8268
8269 CheckLastTempIsBakerCcEntrypointRegister(instruction);
8270 uint32_t custom_data =
8271 linker::Thumb2RelativePatcher::EncodeBakerReadBarrierArrayData(data_reg);
8272 Label* bne_label = NewBakerReadBarrierPatch(custom_data);
8273
8274 // entrypoint_reg =
8275 // Thread::Current()->pReadBarrierMarkReg16, i.e. pReadBarrierMarkIntrospection.
8276 DCHECK_EQ(IP, 12);
8277 const int32_t entry_point_offset =
8278 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(IP);
8279 __ LoadFromOffset(kLoadWord, kBakerCcEntrypointRegister, TR, entry_point_offset);
8280 __ AddConstant(data_reg, obj, data_offset);
8281
8282 Label return_address;
8283 __ AdrCode(LR, &return_address);
8284 __ CmpConstant(kBakerCcEntrypointRegister, 0);
8285 ScopedForce32Bit force_32bit(down_cast<Thumb2Assembler*>(GetAssembler()));
8286 EmitPlaceholderBne(this, bne_label);
8287 static_assert(BAKER_MARK_INTROSPECTION_ARRAY_LDR_OFFSET == (kPoisonHeapReferences ? -8 : -4),
8288 "Array LDR must be 1 32-bit instruction (4B) before the return address label; "
8289 " 2 32-bit instructions (8B) for heap poisoning.");
8290 __ ldr(ref_reg, Address(data_reg, index_reg, LSL, scale_factor));
8291 DCHECK(!needs_null_check); // The thunk cannot handle the null check.
8292 GetAssembler()->MaybeUnpoisonHeapReference(ref_reg);
8293 __ Bind(&return_address);
8294 return;
8295 }
8296
Roland Levillainc9285912015-12-18 10:38:42 +00008297 // /* HeapReference<Object> */ ref =
8298 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
8299 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008300 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008301}
8302
8303void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
8304 Location ref,
8305 Register obj,
8306 uint32_t offset,
8307 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01008308 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00008309 Location temp,
Roland Levillainff487002017-03-07 16:50:01 +00008310 bool needs_null_check) {
Roland Levillainc9285912015-12-18 10:38:42 +00008311 DCHECK(kEmitCompilerReadBarrier);
8312 DCHECK(kUseBakerReadBarrier);
8313
Roland Levillain54f869e2017-03-06 13:54:11 +00008314 // Query `art::Thread::Current()->GetIsGcMarking()` to decide
8315 // whether we need to enter the slow path to mark the reference.
8316 // Then, in the slow path, check the gray bit in the lock word of
8317 // the reference's holder (`obj`) to decide whether to mark `ref` or
8318 // not.
Roland Levillainc9285912015-12-18 10:38:42 +00008319 //
Roland Levillainba650a42017-03-06 13:52:32 +00008320 // Note that we do not actually check the value of `GetIsGcMarking()`;
Roland Levillainff487002017-03-07 16:50:01 +00008321 // instead, we load into `temp2` the read barrier mark entry point
8322 // corresponding to register `ref`. If `temp2` is null, it means
8323 // that `GetIsGcMarking()` is false, and vice versa.
8324 //
8325 // temp2 = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8326 // if (temp2 != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8327 // // Slow path.
8328 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8329 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
8330 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8331 // bool is_gray = (rb_state == ReadBarrier::GrayState());
8332 // if (is_gray) {
8333 // ref = temp2(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
8334 // }
8335 // } else {
8336 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8337 // }
8338
8339 Register temp_reg = temp.AsRegister<Register>();
8340
8341 // Slow path marking the object `ref` when the GC is marking. The
8342 // entrypoint will already be loaded in `temp2`.
8343 Location temp2 = Location::RegisterLocation(LR);
8344 SlowPathCodeARM* slow_path =
8345 new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierSlowPathARM(
8346 instruction,
8347 ref,
8348 obj,
8349 offset,
8350 index,
8351 scale_factor,
8352 needs_null_check,
8353 temp_reg,
8354 /* entrypoint */ temp2);
8355 AddSlowPath(slow_path);
8356
8357 // temp2 = Thread::Current()->pReadBarrierMarkReg ## ref.reg()
8358 const int32_t entry_point_offset =
8359 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref.reg());
8360 // Loading the entrypoint does not require a load acquire since it is only changed when
8361 // threads are suspended or running a checkpoint.
8362 __ LoadFromOffset(kLoadWord, temp2.AsRegister<Register>(), TR, entry_point_offset);
8363 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8364 // checking GetIsGcMarking.
8365 __ CompareAndBranchIfNonZero(temp2.AsRegister<Register>(), slow_path->GetEntryLabel());
8366 // Fast path: the GC is not marking: just load the reference.
8367 GenerateRawReferenceLoad(instruction, ref, obj, offset, index, scale_factor, needs_null_check);
8368 __ Bind(slow_path->GetExitLabel());
8369}
8370
8371void CodeGeneratorARM::UpdateReferenceFieldWithBakerReadBarrier(HInstruction* instruction,
8372 Location ref,
8373 Register obj,
8374 Location field_offset,
8375 Location temp,
8376 bool needs_null_check,
8377 Register temp2) {
8378 DCHECK(kEmitCompilerReadBarrier);
8379 DCHECK(kUseBakerReadBarrier);
8380
8381 // Query `art::Thread::Current()->GetIsGcMarking()` to decide
8382 // whether we need to enter the slow path to update the reference
8383 // field within `obj`. Then, in the slow path, check the gray bit
8384 // in the lock word of the reference's holder (`obj`) to decide
8385 // whether to mark `ref` and update the field or not.
8386 //
8387 // Note that we do not actually check the value of `GetIsGcMarking()`;
Roland Levillainba650a42017-03-06 13:52:32 +00008388 // instead, we load into `temp3` the read barrier mark entry point
8389 // corresponding to register `ref`. If `temp3` is null, it means
8390 // that `GetIsGcMarking()` is false, and vice versa.
8391 //
8392 // temp3 = Thread::Current()->pReadBarrierMarkReg ## root.reg()
Roland Levillainba650a42017-03-06 13:52:32 +00008393 // if (temp3 != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8394 // // Slow path.
Roland Levillain54f869e2017-03-06 13:54:11 +00008395 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8396 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
8397 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8398 // bool is_gray = (rb_state == ReadBarrier::GrayState());
8399 // if (is_gray) {
Roland Levillainff487002017-03-07 16:50:01 +00008400 // old_ref = ref;
Roland Levillain54f869e2017-03-06 13:54:11 +00008401 // ref = temp3(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
Roland Levillainff487002017-03-07 16:50:01 +00008402 // compareAndSwapObject(obj, field_offset, old_ref, ref);
Roland Levillain54f869e2017-03-06 13:54:11 +00008403 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008404 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008405
Roland Levillain35345a52017-02-27 14:32:08 +00008406 Register temp_reg = temp.AsRegister<Register>();
Roland Levillain1372c9f2017-01-13 11:47:39 +00008407
Roland Levillainff487002017-03-07 16:50:01 +00008408 // Slow path updating the object reference at address `obj +
8409 // field_offset` when the GC is marking. The entrypoint will already
8410 // be loaded in `temp3`.
Roland Levillainba650a42017-03-06 13:52:32 +00008411 Location temp3 = Location::RegisterLocation(LR);
Roland Levillainff487002017-03-07 16:50:01 +00008412 SlowPathCodeARM* slow_path =
8413 new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(
8414 instruction,
8415 ref,
8416 obj,
8417 /* offset */ 0u,
8418 /* index */ field_offset,
8419 /* scale_factor */ ScaleFactor::TIMES_1,
8420 needs_null_check,
8421 temp_reg,
8422 temp2,
8423 /* entrypoint */ temp3);
Roland Levillainba650a42017-03-06 13:52:32 +00008424 AddSlowPath(slow_path);
Roland Levillain35345a52017-02-27 14:32:08 +00008425
Roland Levillainba650a42017-03-06 13:52:32 +00008426 // temp3 = Thread::Current()->pReadBarrierMarkReg ## ref.reg()
8427 const int32_t entry_point_offset =
8428 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref.reg());
8429 // Loading the entrypoint does not require a load acquire since it is only changed when
8430 // threads are suspended or running a checkpoint.
8431 __ LoadFromOffset(kLoadWord, temp3.AsRegister<Register>(), TR, entry_point_offset);
Roland Levillainba650a42017-03-06 13:52:32 +00008432 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8433 // checking GetIsGcMarking.
8434 __ CompareAndBranchIfNonZero(temp3.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillainff487002017-03-07 16:50:01 +00008435 // Fast path: the GC is not marking: nothing to do (the field is
8436 // up-to-date, and we don't need to load the reference).
Roland Levillainba650a42017-03-06 13:52:32 +00008437 __ Bind(slow_path->GetExitLabel());
8438}
Roland Levillain35345a52017-02-27 14:32:08 +00008439
Roland Levillainba650a42017-03-06 13:52:32 +00008440void CodeGeneratorARM::GenerateRawReferenceLoad(HInstruction* instruction,
8441 Location ref,
8442 Register obj,
8443 uint32_t offset,
8444 Location index,
8445 ScaleFactor scale_factor,
8446 bool needs_null_check) {
8447 Register ref_reg = ref.AsRegister<Register>();
8448
Roland Levillainc9285912015-12-18 10:38:42 +00008449 if (index.IsValid()) {
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008450 // Load types involving an "index": ArrayGet,
8451 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8452 // intrinsics.
Roland Levillainba650a42017-03-06 13:52:32 +00008453 // /* HeapReference<mirror::Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00008454 if (index.IsConstant()) {
8455 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01008456 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00008457 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
8458 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01008459 // Handle the special case of the
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008460 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8461 // intrinsics, which use a register pair as index ("long
8462 // offset"), of which only the low part contains data.
Roland Levillainbfea3352016-06-23 13:48:47 +01008463 Register index_reg = index.IsRegisterPair()
8464 ? index.AsRegisterPairLow<Register>()
8465 : index.AsRegister<Register>();
8466 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00008467 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
8468 }
8469 } else {
Roland Levillainba650a42017-03-06 13:52:32 +00008470 // /* HeapReference<mirror::Object> */ ref = *(obj + offset)
Roland Levillainc9285912015-12-18 10:38:42 +00008471 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
8472 }
8473
Roland Levillainba650a42017-03-06 13:52:32 +00008474 if (needs_null_check) {
8475 MaybeRecordImplicitNullCheck(instruction);
8476 }
8477
Roland Levillainc9285912015-12-18 10:38:42 +00008478 // Object* ref = ref_addr->AsMirrorPtr()
8479 __ MaybeUnpoisonHeapReference(ref_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00008480}
8481
8482void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
8483 Location out,
8484 Location ref,
8485 Location obj,
8486 uint32_t offset,
8487 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008488 DCHECK(kEmitCompilerReadBarrier);
8489
Roland Levillainc9285912015-12-18 10:38:42 +00008490 // Insert a slow path based read barrier *after* the reference load.
8491 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008492 // If heap poisoning is enabled, the unpoisoning of the loaded
8493 // reference will be carried out by the runtime within the slow
8494 // path.
8495 //
8496 // Note that `ref` currently does not get unpoisoned (when heap
8497 // poisoning is enabled), which is alright as the `ref` argument is
8498 // not used by the artReadBarrierSlow entry point.
8499 //
8500 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008501 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
Roland Levillain3b359c72015-11-17 19:35:12 +00008502 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
8503 AddSlowPath(slow_path);
8504
Roland Levillain3b359c72015-11-17 19:35:12 +00008505 __ b(slow_path->GetEntryLabel());
8506 __ Bind(slow_path->GetExitLabel());
8507}
8508
Roland Levillainc9285912015-12-18 10:38:42 +00008509void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
8510 Location out,
8511 Location ref,
8512 Location obj,
8513 uint32_t offset,
8514 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008515 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00008516 // Baker's read barriers shall be handled by the fast path
8517 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
8518 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00008519 // If heap poisoning is enabled, unpoisoning will be taken care of
8520 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00008521 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00008522 } else if (kPoisonHeapReferences) {
8523 __ UnpoisonHeapReference(out.AsRegister<Register>());
8524 }
8525}
8526
Roland Levillainc9285912015-12-18 10:38:42 +00008527void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
8528 Location out,
8529 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008530 DCHECK(kEmitCompilerReadBarrier);
8531
Roland Levillainc9285912015-12-18 10:38:42 +00008532 // Insert a slow path based read barrier *after* the GC root load.
8533 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008534 // Note that GC roots are not affected by heap poisoning, so we do
8535 // not need to do anything special for this here.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008536 SlowPathCodeARM* slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00008537 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
8538 AddSlowPath(slow_path);
8539
Roland Levillain3b359c72015-11-17 19:35:12 +00008540 __ b(slow_path->GetEntryLabel());
8541 __ Bind(slow_path->GetExitLabel());
8542}
8543
Vladimir Markodc151b22015-10-15 18:02:30 +01008544HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
8545 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +00008546 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffraye807ff72017-01-23 09:03:12 +00008547 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01008548}
8549
Vladimir Markob4536b72015-11-24 13:45:23 +00008550Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
8551 Register temp) {
8552 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
8553 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
8554 if (!invoke->GetLocations()->Intrinsified()) {
8555 return location.AsRegister<Register>();
8556 }
8557 // For intrinsics we allow any location, so it may be on the stack.
8558 if (!location.IsRegister()) {
8559 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
8560 return temp;
8561 }
8562 // For register locations, check if the register was saved. If so, get it from the stack.
8563 // Note: There is a chance that the register was saved but not overwritten, so we could
8564 // save one load. However, since this is just an intrinsic slow path we prefer this
8565 // simple and more robust approach rather that trying to determine if that's the case.
8566 SlowPathCode* slow_path = GetCurrentSlowPath();
TatWai Chongd8c052a2016-11-02 16:12:48 +08008567 if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
Vladimir Markob4536b72015-11-24 13:45:23 +00008568 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
8569 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
8570 return temp;
8571 }
8572 return location.AsRegister<Register>();
8573}
8574
TatWai Chongd8c052a2016-11-02 16:12:48 +08008575Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
8576 Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00008577 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
8578 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008579 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
8580 uint32_t offset =
8581 GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Vladimir Marko58155012015-08-19 12:49:41 +00008582 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008583 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
Vladimir Marko58155012015-08-19 12:49:41 +00008584 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008585 }
Vladimir Marko58155012015-08-19 12:49:41 +00008586 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00008587 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00008588 break;
8589 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
8590 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
8591 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00008592 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
8593 HArmDexCacheArraysBase* base =
8594 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
8595 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
8596 temp.AsRegister<Register>());
8597 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
8598 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
8599 break;
8600 }
Vladimir Marko58155012015-08-19 12:49:41 +00008601 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00008602 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00008603 Register method_reg;
8604 Register reg = temp.AsRegister<Register>();
8605 if (current_method.IsRegister()) {
8606 method_reg = current_method.AsRegister<Register>();
8607 } else {
8608 DCHECK(invoke->GetLocations()->Intrinsified());
8609 DCHECK(!current_method.IsValid());
8610 method_reg = reg;
8611 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
8612 }
Roland Levillain3b359c72015-11-17 19:35:12 +00008613 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
8614 __ LoadFromOffset(kLoadWord,
8615 reg,
8616 method_reg,
8617 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01008618 // temp = temp[index_in_cache];
8619 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
8620 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00008621 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
8622 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01008623 }
Vladimir Marko58155012015-08-19 12:49:41 +00008624 }
TatWai Chongd8c052a2016-11-02 16:12:48 +08008625 return callee_method;
8626}
8627
8628void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
8629 Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
Vladimir Marko58155012015-08-19 12:49:41 +00008630
8631 switch (invoke->GetCodePtrLocation()) {
8632 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
8633 __ bl(GetFrameEntryLabel());
8634 break;
Vladimir Marko58155012015-08-19 12:49:41 +00008635 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
8636 // LR = callee_method->entry_point_from_quick_compiled_code_
8637 __ LoadFromOffset(
8638 kLoadWord, LR, callee_method.AsRegister<Register>(),
Andreas Gampe542451c2016-07-26 09:02:02 -07008639 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00008640 // LR()
8641 __ blx(LR);
8642 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08008643 }
8644
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08008645 DCHECK(!IsLeafMethod());
8646}
8647
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008648void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
8649 Register temp = temp_location.AsRegister<Register>();
8650 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
8651 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00008652
8653 // Use the calling convention instead of the location of the receiver, as
8654 // intrinsics may have put the receiver in a different register. In the intrinsics
8655 // slow path, the arguments have been moved to the right place, so here we are
8656 // guaranteed that the receiver is the first register of the calling convention.
8657 InvokeDexCallingConvention calling_convention;
8658 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008659 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00008660 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00008661 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008662 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00008663 // Instead of simply (possibly) unpoisoning `temp` here, we should
8664 // emit a read barrier for the previous class reference load.
8665 // However this is not required in practice, as this is an
8666 // intermediate/temporary reference and because the current
8667 // concurrent copying collector keeps the from-space memory
8668 // intact/accessible until the end of the marking phase (the
8669 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008670 __ MaybeUnpoisonHeapReference(temp);
8671 // temp = temp->GetMethodAt(method_offset);
8672 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07008673 kArmPointerSize).Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008674 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
8675 // LR = temp->GetEntryPoint();
8676 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
8677 // LR();
8678 __ blx(LR);
8679}
8680
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008681CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008682 const DexFile& dex_file, dex::StringIndex string_index) {
8683 return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008684}
8685
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008686CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
Andreas Gampea5b09a62016-11-17 15:21:22 -08008687 const DexFile& dex_file, dex::TypeIndex type_index) {
8688 return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008689}
8690
Vladimir Marko1998cd02017-01-13 13:02:58 +00008691CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
8692 const DexFile& dex_file, dex::TypeIndex type_index) {
8693 return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
8694}
8695
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008696CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
8697 const DexFile& dex_file, uint32_t element_offset) {
8698 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
8699}
8700
8701CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
8702 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
8703 patches->emplace_back(dex_file, offset_or_index);
8704 return &patches->back();
8705}
8706
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008707Label* CodeGeneratorARM::NewBakerReadBarrierPatch(uint32_t custom_data) {
8708 baker_read_barrier_patches_.emplace_back(custom_data);
8709 return &baker_read_barrier_patches_.back().label;
8710}
8711
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008712Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008713 dex::StringIndex string_index) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008714 return boot_image_string_patches_.GetOrCreate(
8715 StringReference(&dex_file, string_index),
8716 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8717}
8718
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008719Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08008720 dex::TypeIndex type_index) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008721 return boot_image_type_patches_.GetOrCreate(
8722 TypeReference(&dex_file, type_index),
8723 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8724}
8725
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008726Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
Richard Uhlerc52f3032017-03-02 13:45:45 +00008727 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008728}
8729
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008730Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00008731 dex::StringIndex string_index,
8732 Handle<mirror::String> handle) {
8733 jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
8734 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008735 return jit_string_patches_.GetOrCreate(
8736 StringReference(&dex_file, string_index),
8737 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8738}
8739
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008740Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
8741 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00008742 Handle<mirror::Class> handle) {
8743 jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
8744 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008745 return jit_class_patches_.GetOrCreate(
8746 TypeReference(&dex_file, type_index),
8747 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8748}
8749
Vladimir Markoaad75c62016-10-03 08:46:48 +00008750template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
8751inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
8752 const ArenaDeque<PcRelativePatchInfo>& infos,
8753 ArenaVector<LinkerPatch>* linker_patches) {
8754 for (const PcRelativePatchInfo& info : infos) {
8755 const DexFile& dex_file = info.target_dex_file;
8756 size_t offset_or_index = info.offset_or_index;
8757 DCHECK(info.add_pc_label.IsBound());
8758 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
8759 // Add MOVW patch.
8760 DCHECK(info.movw_label.IsBound());
8761 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
8762 linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
8763 // Add MOVT patch.
8764 DCHECK(info.movt_label.IsBound());
8765 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
8766 linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
8767 }
8768}
8769
Vladimir Marko58155012015-08-19 12:49:41 +00008770void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
8771 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00008772 size_t size =
Vladimir Markoaad75c62016-10-03 08:46:48 +00008773 /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008774 boot_image_string_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00008775 /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008776 boot_image_type_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00008777 /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008778 /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
8779 baker_read_barrier_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00008780 linker_patches->reserve(size);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008781 EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
8782 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008783 for (const auto& entry : boot_image_string_patches_) {
8784 const StringReference& target_string = entry.first;
8785 Literal* literal = entry.second;
8786 DCHECK(literal->GetLabel()->IsBound());
8787 uint32_t literal_offset = literal->GetLabel()->Position();
8788 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
8789 target_string.dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008790 target_string.string_index.index_));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008791 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00008792 if (!GetCompilerOptions().IsBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00008793 DCHECK(pc_relative_type_patches_.empty());
Vladimir Markoaad75c62016-10-03 08:46:48 +00008794 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
8795 linker_patches);
8796 } else {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008797 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
8798 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008799 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
8800 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008801 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00008802 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
8803 linker_patches);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008804 for (const auto& entry : boot_image_type_patches_) {
8805 const TypeReference& target_type = entry.first;
8806 Literal* literal = entry.second;
8807 DCHECK(literal->GetLabel()->IsBound());
8808 uint32_t literal_offset = literal->GetLabel()->Position();
8809 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
8810 target_type.dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08008811 target_type.type_index.index_));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008812 }
Vladimir Markoeee1c0e2017-04-21 17:58:41 +01008813 for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
8814 linker_patches->push_back(LinkerPatch::BakerReadBarrierBranchPatch(info.label.Position(),
8815 info.custom_data));
8816 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00008817 DCHECK_EQ(size, linker_patches->size());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008818}
8819
8820Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
8821 return map->GetOrCreate(
8822 value,
8823 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00008824}
8825
8826Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
8827 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008828 return map->GetOrCreate(
8829 target_method,
8830 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00008831}
8832
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03008833void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8834 LocationSummary* locations =
8835 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
8836 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
8837 Location::RequiresRegister());
8838 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
8839 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
8840 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8841}
8842
8843void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8844 LocationSummary* locations = instr->GetLocations();
8845 Register res = locations->Out().AsRegister<Register>();
8846 Register accumulator =
8847 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
8848 Register mul_left =
8849 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
8850 Register mul_right =
8851 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
8852
8853 if (instr->GetOpKind() == HInstruction::kAdd) {
8854 __ mla(res, mul_left, mul_right, accumulator);
8855 } else {
8856 __ mls(res, mul_left, mul_right, accumulator);
8857 }
8858}
8859
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008860void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008861 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008862 LOG(FATAL) << "Unreachable";
8863}
8864
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008865void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008866 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008867 LOG(FATAL) << "Unreachable";
8868}
8869
Mark Mendellfe57faa2015-09-18 09:26:15 -04008870// Simple implementation of packed switch - generate cascaded compare/jumps.
8871void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8872 LocationSummary* locations =
8873 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8874 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008875 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008876 codegen_->GetAssembler()->IsThumb()) {
8877 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
8878 if (switch_instr->GetStartValue() != 0) {
8879 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
8880 }
8881 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04008882}
8883
8884void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8885 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008886 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04008887 LocationSummary* locations = switch_instr->GetLocations();
8888 Register value_reg = locations->InAt(0).AsRegister<Register>();
8889 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8890
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008891 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008892 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008893 Register temp_reg = IP;
8894 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
8895 // the immediate, because IP is used as the destination register. For the other
8896 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
8897 // and they can be encoded in the instruction without making use of IP register.
8898 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
8899
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008900 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008901 // Jump to successors[0] if value == lower_bound.
8902 __ b(codegen_->GetLabelOf(successors[0]), EQ);
8903 int32_t last_index = 0;
8904 for (; num_entries - last_index > 2; last_index += 2) {
8905 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
8906 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
8907 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
8908 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
8909 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
8910 }
8911 if (num_entries - last_index == 2) {
8912 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00008913 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008914 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008915 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04008916
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008917 // And the default for any other value.
8918 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
8919 __ b(codegen_->GetLabelOf(default_block));
8920 }
8921 } else {
8922 // Create a table lookup.
8923 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
8924
8925 // Materialize a pointer to the switch table
8926 std::vector<Label*> labels(num_entries);
8927 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
8928 for (uint32_t i = 0; i < num_entries; i++) {
8929 labels[i] = codegen_->GetLabelOf(successors[i]);
8930 }
8931 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
8932
8933 // Remove the bias.
8934 Register key_reg;
8935 if (lower_bound != 0) {
8936 key_reg = locations->GetTemp(1).AsRegister<Register>();
8937 __ AddConstant(key_reg, value_reg, -lower_bound);
8938 } else {
8939 key_reg = value_reg;
8940 }
8941
8942 // Check whether the value is in the table, jump to default block if not.
8943 __ CmpConstant(key_reg, num_entries - 1);
8944 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
8945
8946 // Load the displacement from the table.
8947 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
8948
8949 // Dispatch is a direct add to the PC (for Thumb2).
8950 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04008951 }
8952}
8953
Vladimir Markob4536b72015-11-24 13:45:23 +00008954void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8955 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
8956 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00008957}
8958
8959void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8960 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008961 CodeGeneratorARM::PcRelativePatchInfo* labels =
8962 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00008963 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008964 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00008965 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008966 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00008967 __ BindTrackedLabel(&labels->add_pc_label);
8968 __ add(base_reg, base_reg, ShifterOperand(PC));
8969}
8970
Andreas Gampe85b62f22015-09-09 13:15:38 -07008971void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
8972 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00008973 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07008974 return;
8975 }
8976
8977 DCHECK_NE(type, Primitive::kPrimVoid);
8978
8979 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
8980 if (return_loc.Equals(trg)) {
8981 return;
8982 }
8983
8984 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
8985 // with the last branch.
8986 if (type == Primitive::kPrimLong) {
8987 HParallelMove parallel_move(GetGraph()->GetArena());
8988 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
8989 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
8990 GetMoveResolver()->EmitNativeCode(&parallel_move);
8991 } else if (type == Primitive::kPrimDouble) {
8992 HParallelMove parallel_move(GetGraph()->GetArena());
8993 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
8994 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
8995 GetMoveResolver()->EmitNativeCode(&parallel_move);
8996 } else {
8997 // Let the parallel move resolver take care of all of this.
8998 HParallelMove parallel_move(GetGraph()->GetArena());
8999 parallel_move.AddMove(return_loc, trg, type, nullptr);
9000 GetMoveResolver()->EmitNativeCode(&parallel_move);
9001 }
9002}
9003
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009004void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
9005 LocationSummary* locations =
9006 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
9007 locations->SetInAt(0, Location::RequiresRegister());
9008 locations->SetOut(Location::RequiresRegister());
9009}
9010
9011void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
9012 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00009013 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009014 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009015 instruction->GetIndex(), kArmPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009016 __ LoadFromOffset(kLoadWord,
9017 locations->Out().AsRegister<Register>(),
9018 locations->InAt(0).AsRegister<Register>(),
9019 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009020 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009021 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00009022 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009023 __ LoadFromOffset(kLoadWord,
9024 locations->Out().AsRegister<Register>(),
9025 locations->InAt(0).AsRegister<Register>(),
9026 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
9027 __ LoadFromOffset(kLoadWord,
9028 locations->Out().AsRegister<Register>(),
9029 locations->Out().AsRegister<Register>(),
9030 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009031 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009032}
9033
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009034static void PatchJitRootUse(uint8_t* code,
9035 const uint8_t* roots_data,
9036 Literal* literal,
9037 uint64_t index_in_table) {
9038 DCHECK(literal->GetLabel()->IsBound());
9039 uint32_t literal_offset = literal->GetLabel()->Position();
9040 uintptr_t address =
9041 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
9042 uint8_t* data = code + literal_offset;
9043 reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
9044}
9045
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009046void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
9047 for (const auto& entry : jit_string_patches_) {
9048 const auto& it = jit_string_roots_.find(entry.first);
9049 DCHECK(it != jit_string_roots_.end());
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009050 PatchJitRootUse(code, roots_data, entry.second, it->second);
9051 }
9052 for (const auto& entry : jit_class_patches_) {
9053 const auto& it = jit_class_roots_.find(entry.first);
9054 DCHECK(it != jit_class_roots_.end());
9055 PatchJitRootUse(code, roots_data, entry.second, it->second);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009056 }
9057}
9058
Roland Levillain4d027112015-07-01 15:41:14 +01009059#undef __
9060#undef QUICK_ENTRY_POINT
9061
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00009062} // namespace arm
9063} // namespace art