blob: d037b94b4a88752bd17d744064b22a7c7e3850e2 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_arm.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000018
Calin Juravle34166012014-12-19 17:22:29 +000019#include "arch/arm/instruction_set_features_arm.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070020#include "art_method.h"
Zheng Xuc6667102015-05-15 16:08:45 +080021#include "code_generator_utils.h"
Anton Kirilov74234da2017-01-13 14:42:47 +000022#include "common_arm.h"
Vladimir Marko58155012015-08-19 12:49:41 +000023#include "compiled_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070024#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010025#include "gc/accounting/card_table.h"
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -080026#include "intrinsics.h"
27#include "intrinsics_arm.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070028#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070029#include "mirror/class-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070030#include "thread.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010031#include "utils/arm/assembler_arm.h"
32#include "utils/arm/managed_register_arm.h"
Roland Levillain946e1432014-11-11 17:35:19 +000033#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010034#include "utils/stack_checks.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000035
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010037
Roland Levillain3b359c72015-11-17 19:35:12 +000038template<class MirrorType>
39class GcRoot;
40
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000041namespace arm {
42
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +000043static bool ExpectedPairLayout(Location location) {
44 // We expected this for both core and fpu register pairs.
45 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high());
46}
47
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010048static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010049static constexpr Register kMethodRegisterArgument = R0;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010050
David Brazdil58282f42016-01-14 12:45:10 +000051static constexpr Register kCoreAlwaysSpillRegister = R5;
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000052static constexpr Register kCoreCalleeSaves[] =
Andreas Gampe501fd632015-09-10 16:11:06 -070053 { R5, R6, R7, R8, R10, R11, LR };
Nicolas Geoffray4dee6362015-01-23 18:23:14 +000054static constexpr SRegister kFpuCalleeSaves[] =
55 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010056
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +000057// D31 cannot be split into two S registers, and the register allocator only works on
58// S registers. Therefore there is no need to block it.
59static constexpr DRegister DTMP = D31;
60
Vladimir Markof3e0ee22015-12-17 15:23:13 +000061static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7;
Andreas Gampe7cffc3b2015-10-19 21:31:53 -070062
Roland Levillain7cbd27f2016-08-11 23:53:33 +010063// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
64#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -070065#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmPointerSize, x).Int32Value()
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066
Artem Serovf4d6aee2016-07-11 10:41:45 +010067static constexpr int kRegListThreshold = 4;
68
Artem Serovd300d8f2016-07-15 14:00:56 +010069// SaveLiveRegisters and RestoreLiveRegisters from SlowPathCodeARM operate on sets of S registers,
70// for each live D registers they treat two corresponding S registers as live ones.
71//
72// Two following functions (SaveContiguousSRegisterList, RestoreContiguousSRegisterList) build
73// from a list of contiguous S registers a list of contiguous D registers (processing first/last
74// S registers corner cases) and save/restore this new list treating them as D registers.
75// - decreasing code size
76// - avoiding hazards on Cortex-A57, when a pair of S registers for an actual live D register is
77// restored and then used in regular non SlowPath code as D register.
78//
79// For the following example (v means the S register is live):
80// D names: | D0 | D1 | D2 | D4 | ...
81// S names: | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | ...
82// Live? | | v | v | v | v | v | v | | ...
83//
84// S1 and S6 will be saved/restored independently; D registers list (D1, D2) will be processed
85// as D registers.
86static size_t SaveContiguousSRegisterList(size_t first,
87 size_t last,
88 CodeGenerator* codegen,
89 size_t stack_offset) {
90 DCHECK_LE(first, last);
91 if ((first == last) && (first == 0)) {
92 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first);
93 return stack_offset;
94 }
95 if (first % 2 == 1) {
96 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, first++);
97 }
98
99 bool save_last = false;
100 if (last % 2 == 0) {
101 save_last = true;
102 --last;
103 }
104
105 if (first < last) {
106 DRegister d_reg = static_cast<DRegister>(first / 2);
107 DCHECK_EQ((last - first + 1) % 2, 0u);
108 size_t number_of_d_regs = (last - first + 1) / 2;
109
110 if (number_of_d_regs == 1) {
Scott Wakelinga7812ae2016-10-17 10:03:36 +0100111 __ StoreDToOffset(d_reg, SP, stack_offset);
Artem Serovd300d8f2016-07-15 14:00:56 +0100112 } else if (number_of_d_regs > 1) {
113 __ add(IP, SP, ShifterOperand(stack_offset));
114 __ vstmiad(IP, d_reg, number_of_d_regs);
115 }
116 stack_offset += number_of_d_regs * kArmWordSize * 2;
117 }
118
119 if (save_last) {
120 stack_offset += codegen->SaveFloatingPointRegister(stack_offset, last + 1);
121 }
122
123 return stack_offset;
124}
125
126static size_t RestoreContiguousSRegisterList(size_t first,
127 size_t last,
128 CodeGenerator* codegen,
129 size_t stack_offset) {
130 DCHECK_LE(first, last);
131 if ((first == last) && (first == 0)) {
132 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first);
133 return stack_offset;
134 }
135 if (first % 2 == 1) {
136 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, first++);
137 }
138
139 bool restore_last = false;
140 if (last % 2 == 0) {
141 restore_last = true;
142 --last;
143 }
144
145 if (first < last) {
146 DRegister d_reg = static_cast<DRegister>(first / 2);
147 DCHECK_EQ((last - first + 1) % 2, 0u);
148 size_t number_of_d_regs = (last - first + 1) / 2;
149 if (number_of_d_regs == 1) {
150 __ LoadDFromOffset(d_reg, SP, stack_offset);
151 } else if (number_of_d_regs > 1) {
152 __ add(IP, SP, ShifterOperand(stack_offset));
153 __ vldmiad(IP, d_reg, number_of_d_regs);
154 }
155 stack_offset += number_of_d_regs * kArmWordSize * 2;
156 }
157
158 if (restore_last) {
159 stack_offset += codegen->RestoreFloatingPointRegister(stack_offset, last + 1);
160 }
161
162 return stack_offset;
163}
164
Artem Serovf4d6aee2016-07-11 10:41:45 +0100165void SlowPathCodeARM::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
166 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
167 size_t orig_offset = stack_offset;
168
169 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
170 for (uint32_t i : LowToHighBits(core_spills)) {
171 // If the register holds an object, update the stack mask.
172 if (locations->RegisterContainsObject(i)) {
173 locations->SetStackBit(stack_offset / kVRegSize);
174 }
175 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
176 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
177 saved_core_stack_offsets_[i] = stack_offset;
178 stack_offset += kArmWordSize;
179 }
180
181 int reg_num = POPCOUNT(core_spills);
182 if (reg_num != 0) {
183 if (reg_num > kRegListThreshold) {
184 __ StoreList(RegList(core_spills), orig_offset);
185 } else {
186 stack_offset = orig_offset;
187 for (uint32_t i : LowToHighBits(core_spills)) {
188 stack_offset += codegen->SaveCoreRegister(stack_offset, i);
189 }
190 }
191 }
192
Artem Serovd300d8f2016-07-15 14:00:56 +0100193 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
194 orig_offset = stack_offset;
Vladimir Marko804b03f2016-09-14 16:26:36 +0100195 for (uint32_t i : LowToHighBits(fp_spills)) {
Artem Serovf4d6aee2016-07-11 10:41:45 +0100196 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
197 saved_fpu_stack_offsets_[i] = stack_offset;
Artem Serovd300d8f2016-07-15 14:00:56 +0100198 stack_offset += kArmWordSize;
Artem Serovf4d6aee2016-07-11 10:41:45 +0100199 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100200
201 stack_offset = orig_offset;
202 while (fp_spills != 0u) {
203 uint32_t begin = CTZ(fp_spills);
204 uint32_t tmp = fp_spills + (1u << begin);
205 fp_spills &= tmp; // Clear the contiguous range of 1s.
206 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
207 stack_offset = SaveContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
208 }
209 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100210}
211
212void SlowPathCodeARM::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
213 size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
214 size_t orig_offset = stack_offset;
215
216 const uint32_t core_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ true);
217 for (uint32_t i : LowToHighBits(core_spills)) {
218 DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
219 DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
220 stack_offset += kArmWordSize;
221 }
222
223 int reg_num = POPCOUNT(core_spills);
224 if (reg_num != 0) {
225 if (reg_num > kRegListThreshold) {
226 __ LoadList(RegList(core_spills), orig_offset);
227 } else {
228 stack_offset = orig_offset;
229 for (uint32_t i : LowToHighBits(core_spills)) {
230 stack_offset += codegen->RestoreCoreRegister(stack_offset, i);
231 }
232 }
233 }
234
Artem Serovd300d8f2016-07-15 14:00:56 +0100235 uint32_t fp_spills = codegen->GetSlowPathSpills(locations, /* core_registers */ false);
236 while (fp_spills != 0u) {
237 uint32_t begin = CTZ(fp_spills);
238 uint32_t tmp = fp_spills + (1u << begin);
239 fp_spills &= tmp; // Clear the contiguous range of 1s.
240 uint32_t end = (tmp == 0u) ? 32u : CTZ(tmp); // CTZ(0) is undefined.
241 stack_offset = RestoreContiguousSRegisterList(begin, end - 1, codegen, stack_offset);
Artem Serovf4d6aee2016-07-11 10:41:45 +0100242 }
Artem Serovd300d8f2016-07-15 14:00:56 +0100243 DCHECK_LE(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
Artem Serovf4d6aee2016-07-11 10:41:45 +0100244}
245
246class NullCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100247 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100248 explicit NullCheckSlowPathARM(HNullCheck* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100249
Alexandre Rames67555f72014-11-18 10:55:16 +0000250 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100251 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100252 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000253 if (instruction_->CanThrowIntoCatchBlock()) {
254 // Live registers will be restored in the catch block if caught.
255 SaveLiveRegisters(codegen, instruction_->GetLocations());
256 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100257 arm_codegen->InvokeRuntime(kQuickThrowNullPointer,
258 instruction_,
259 instruction_->GetDexPc(),
260 this);
Roland Levillain888d0672015-11-23 18:53:50 +0000261 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100262 }
263
Alexandre Rames8158f282015-08-07 10:26:17 +0100264 bool IsFatal() const OVERRIDE { return true; }
265
Alexandre Rames9931f312015-06-19 14:47:01 +0100266 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
267
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100268 private:
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100269 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
270};
271
Artem Serovf4d6aee2016-07-11 10:41:45 +0100272class DivZeroCheckSlowPathARM : public SlowPathCodeARM {
Calin Juravled0d48522014-11-04 16:40:20 +0000273 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100274 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : SlowPathCodeARM(instruction) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000275
Alexandre Rames67555f72014-11-18 10:55:16 +0000276 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000277 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
278 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100279 arm_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000280 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
Calin Juravled0d48522014-11-04 16:40:20 +0000281 }
282
Alexandre Rames8158f282015-08-07 10:26:17 +0100283 bool IsFatal() const OVERRIDE { return true; }
284
Alexandre Rames9931f312015-06-19 14:47:01 +0100285 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
286
Calin Juravled0d48522014-11-04 16:40:20 +0000287 private:
Calin Juravled0d48522014-11-04 16:40:20 +0000288 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
289};
290
Artem Serovf4d6aee2016-07-11 10:41:45 +0100291class SuspendCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000292 public:
Alexandre Rames67555f72014-11-18 10:55:16 +0000293 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100294 : SlowPathCodeARM(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000295
Alexandre Rames67555f72014-11-18 10:55:16 +0000296 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100297 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000298 __ Bind(GetEntryLabel());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100299 arm_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000300 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100301 if (successor_ == nullptr) {
302 __ b(GetReturnLabel());
303 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100304 __ b(arm_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100305 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000306 }
307
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100308 Label* GetReturnLabel() {
309 DCHECK(successor_ == nullptr);
310 return &return_label_;
311 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000312
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100313 HBasicBlock* GetSuccessor() const {
314 return successor_;
315 }
316
Alexandre Rames9931f312015-06-19 14:47:01 +0100317 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
318
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000319 private:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100320 // If not null, the block to branch to after the suspend check.
321 HBasicBlock* const successor_;
322
323 // If `successor_` is null, the label to branch to after the suspend check.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000324 Label return_label_;
325
326 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
327};
328
Artem Serovf4d6aee2016-07-11 10:41:45 +0100329class BoundsCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100330 public:
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100331 explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100332 : SlowPathCodeARM(instruction) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100333
Alexandre Rames67555f72014-11-18 10:55:16 +0000334 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100335 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100336 LocationSummary* locations = instruction_->GetLocations();
337
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100338 __ Bind(GetEntryLabel());
David Brazdil77a48ae2015-09-15 12:34:04 +0000339 if (instruction_->CanThrowIntoCatchBlock()) {
340 // Live registers will be restored in the catch block if caught.
341 SaveLiveRegisters(codegen, instruction_->GetLocations());
342 }
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000343 // We're moving two locations to locations that could overlap, so we need a parallel
344 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100345 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000346 codegen->EmitParallelMoves(
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100347 locations->InAt(0),
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000348 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100349 Primitive::kPrimInt,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100350 locations->InAt(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100351 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
352 Primitive::kPrimInt);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100353 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
354 ? kQuickThrowStringBounds
355 : kQuickThrowArrayBounds;
356 arm_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100357 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Roland Levillain888d0672015-11-23 18:53:50 +0000358 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100359 }
360
Alexandre Rames8158f282015-08-07 10:26:17 +0100361 bool IsFatal() const OVERRIDE { return true; }
362
Alexandre Rames9931f312015-06-19 14:47:01 +0100363 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
364
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100365 private:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100366 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
367};
368
Artem Serovf4d6aee2016-07-11 10:41:45 +0100369class LoadClassSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100370 public:
Vladimir Markoea4c1262017-02-06 19:59:33 +0000371 LoadClassSlowPathARM(HLoadClass* cls, HInstruction* at, uint32_t dex_pc, bool do_clinit)
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000372 : SlowPathCodeARM(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000373 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
374 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100375
Alexandre Rames67555f72014-11-18 10:55:16 +0000376 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000377 LocationSummary* locations = instruction_->GetLocations();
Vladimir Markoea4c1262017-02-06 19:59:33 +0000378 Location out = locations->Out();
379 constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000380
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100381 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
382 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000383 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100384
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100385 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoea4c1262017-02-06 19:59:33 +0000386 // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
387 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
388 bool is_load_class_bss_entry =
389 (cls_ == instruction_) && (cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry);
390 Register entry_address = kNoRegister;
391 if (is_load_class_bss_entry && call_saves_everything_except_r0) {
392 Register temp = locations->GetTemp(0).AsRegister<Register>();
393 // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
394 // the kSaveEverything call.
395 bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
396 entry_address = temp_is_r0 ? out.AsRegister<Register>() : temp;
397 DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
398 if (temp_is_r0) {
399 __ mov(entry_address, ShifterOperand(temp));
400 }
401 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000402 dex::TypeIndex type_index = cls_->GetTypeIndex();
403 __ LoadImmediate(calling_convention.GetRegisterAt(0), type_index.index_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100404 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
405 : kQuickInitializeType;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000406 arm_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000407 if (do_clinit_) {
408 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
409 } else {
410 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
411 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000412
Vladimir Markoea4c1262017-02-06 19:59:33 +0000413 // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
414 if (is_load_class_bss_entry) {
415 if (call_saves_everything_except_r0) {
416 // The class entry address was preserved in `entry_address` thanks to kSaveEverything.
417 __ str(R0, Address(entry_address));
418 } else {
419 // For non-Baker read barrier, we need to re-calculate the address of the string entry.
420 Register temp = IP;
421 CodeGeneratorARM::PcRelativePatchInfo* labels =
422 arm_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
423 __ BindTrackedLabel(&labels->movw_label);
424 __ movw(temp, /* placeholder */ 0u);
425 __ BindTrackedLabel(&labels->movt_label);
426 __ movt(temp, /* placeholder */ 0u);
427 __ BindTrackedLabel(&labels->add_pc_label);
428 __ add(temp, temp, ShifterOperand(PC));
429 __ str(R0, Address(temp));
430 }
431 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000432 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000433 if (out.IsValid()) {
434 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000435 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
436 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000437 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100438 __ b(GetExitLabel());
439 }
440
Alexandre Rames9931f312015-06-19 14:47:01 +0100441 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
442
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100443 private:
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000444 // The class this slow path will load.
445 HLoadClass* const cls_;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100446
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000447 // The dex PC of `at_`.
448 const uint32_t dex_pc_;
449
450 // Whether to initialize the class.
451 const bool do_clinit_;
452
453 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100454};
455
Vladimir Markoaad75c62016-10-03 08:46:48 +0000456class LoadStringSlowPathARM : public SlowPathCodeARM {
457 public:
458 explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCodeARM(instruction) {}
459
460 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Markoea4c1262017-02-06 19:59:33 +0000461 DCHECK(instruction_->IsLoadString());
462 DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000463 LocationSummary* locations = instruction_->GetLocations();
464 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100465 HLoadString* load = instruction_->AsLoadString();
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000466 const dex::StringIndex string_index = load->GetStringIndex();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100467 Register out = locations->Out().AsRegister<Register>();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100468 constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000469
470 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
471 __ Bind(GetEntryLabel());
472 SaveLiveRegisters(codegen, locations);
473
474 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100475 // In the unlucky case that the `temp` is R0, we preserve the address in `out` across
Vladimir Markoea4c1262017-02-06 19:59:33 +0000476 // the kSaveEverything call.
477 Register entry_address = kNoRegister;
478 if (call_saves_everything_except_r0) {
479 Register temp = locations->GetTemp(0).AsRegister<Register>();
480 bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0));
481 entry_address = temp_is_r0 ? out : temp;
482 DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
483 if (temp_is_r0) {
484 __ mov(entry_address, ShifterOperand(temp));
485 }
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100486 }
487
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000488 __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index.index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000489 arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
490 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100491
492 // Store the resolved String to the .bss entry.
493 if (call_saves_everything_except_r0) {
494 // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
495 __ str(R0, Address(entry_address));
496 } else {
497 // For non-Baker read barrier, we need to re-calculate the address of the string entry.
Vladimir Markoea4c1262017-02-06 19:59:33 +0000498 Register temp = IP;
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100499 CodeGeneratorARM::PcRelativePatchInfo* labels =
500 arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
501 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000502 __ movw(temp, /* placeholder */ 0u);
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100503 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000504 __ movt(temp, /* placeholder */ 0u);
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100505 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +0000506 __ add(temp, temp, ShifterOperand(PC));
507 __ str(R0, Address(temp));
Vladimir Marko94ce9c22016-09-30 14:50:51 +0100508 }
509
Vladimir Markoaad75c62016-10-03 08:46:48 +0000510 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
Vladimir Markoaad75c62016-10-03 08:46:48 +0000511 RestoreLiveRegisters(codegen, locations);
512
Vladimir Markoaad75c62016-10-03 08:46:48 +0000513 __ b(GetExitLabel());
514 }
515
516 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
517
518 private:
519 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
520};
521
Artem Serovf4d6aee2016-07-11 10:41:45 +0100522class TypeCheckSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000523 public:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000524 TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100525 : SlowPathCodeARM(instruction), is_fatal_(is_fatal) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000526
Alexandre Rames67555f72014-11-18 10:55:16 +0000527 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000528 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000529 DCHECK(instruction_->IsCheckCast()
530 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000531
532 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
533 __ Bind(GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000534
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000535 if (!is_fatal_) {
536 SaveLiveRegisters(codegen, locations);
537 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000538
539 // We're moving two locations to locations that could overlap, so we need a parallel
540 // move resolver.
541 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800542 codegen->EmitParallelMoves(locations->InAt(0),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800543 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
544 Primitive::kPrimNot,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800545 locations->InAt(1),
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800546 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
547 Primitive::kPrimNot);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000548 if (instruction_->IsInstanceOf()) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100549 arm_codegen->InvokeRuntime(kQuickInstanceofNonTrivial,
Serban Constantinescu5a6cc492015-08-13 15:20:25 +0100550 instruction_,
551 instruction_->GetDexPc(),
552 this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800553 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000554 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
555 } else {
556 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800557 arm_codegen->InvokeRuntime(kQuickCheckInstanceOf,
558 instruction_,
559 instruction_->GetDexPc(),
560 this);
561 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000562 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000563
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000564 if (!is_fatal_) {
565 RestoreLiveRegisters(codegen, locations);
566 __ b(GetExitLabel());
567 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000568 }
569
Alexandre Rames9931f312015-06-19 14:47:01 +0100570 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
571
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000572 bool IsFatal() const OVERRIDE { return is_fatal_; }
573
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000574 private:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +0000575 const bool is_fatal_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000576
577 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM);
578};
579
Artem Serovf4d6aee2016-07-11 10:41:45 +0100580class DeoptimizationSlowPathARM : public SlowPathCodeARM {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700581 public:
Aart Bik42249c32016-01-07 15:33:50 -0800582 explicit DeoptimizationSlowPathARM(HDeoptimize* instruction)
Artem Serovf4d6aee2016-07-11 10:41:45 +0100583 : SlowPathCodeARM(instruction) {}
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700584
585 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800586 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700587 __ Bind(GetEntryLabel());
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100588 LocationSummary* locations = instruction_->GetLocations();
589 SaveLiveRegisters(codegen, locations);
590 InvokeRuntimeCallingConvention calling_convention;
591 __ LoadImmediate(calling_convention.GetRegisterAt(0),
592 static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100593 arm_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100594 CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700595 }
596
Alexandre Rames9931f312015-06-19 14:47:01 +0100597 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
598
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700599 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700600 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
601};
602
Artem Serovf4d6aee2016-07-11 10:41:45 +0100603class ArraySetSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100604 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100605 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100606
607 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
608 LocationSummary* locations = instruction_->GetLocations();
609 __ Bind(GetEntryLabel());
610 SaveLiveRegisters(codegen, locations);
611
612 InvokeRuntimeCallingConvention calling_convention;
613 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
614 parallel_move.AddMove(
615 locations->InAt(0),
616 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
617 Primitive::kPrimNot,
618 nullptr);
619 parallel_move.AddMove(
620 locations->InAt(1),
621 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
622 Primitive::kPrimInt,
623 nullptr);
624 parallel_move.AddMove(
625 locations->InAt(2),
626 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
627 Primitive::kPrimNot,
628 nullptr);
629 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
630
631 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100632 arm_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000633 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100634 RestoreLiveRegisters(codegen, locations);
635 __ b(GetExitLabel());
636 }
637
638 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
639
640 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100641 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
642};
643
Roland Levillain54f869e2017-03-06 13:54:11 +0000644// Abstract base class for read barrier slow paths marking a reference
645// `ref`.
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000646//
Roland Levillain54f869e2017-03-06 13:54:11 +0000647// Argument `entrypoint` must be a register location holding the read
648// barrier marking runtime entry point to be invoked.
649class ReadBarrierMarkSlowPathBaseARM : public SlowPathCodeARM {
650 protected:
651 ReadBarrierMarkSlowPathBaseARM(HInstruction* instruction, Location ref, Location entrypoint)
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000652 : SlowPathCodeARM(instruction), ref_(ref), entrypoint_(entrypoint) {
653 DCHECK(kEmitCompilerReadBarrier);
654 }
655
Roland Levillain54f869e2017-03-06 13:54:11 +0000656 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathBaseARM"; }
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000657
Roland Levillain54f869e2017-03-06 13:54:11 +0000658 // Generate assembly code calling the read barrier marking runtime
659 // entry point (ReadBarrierMarkRegX).
660 void GenerateReadBarrierMarkRuntimeCall(CodeGenerator* codegen) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000661 Register ref_reg = ref_.AsRegister<Register>();
Roland Levillain47b3ab22017-02-27 14:31:35 +0000662
Roland Levillain47b3ab22017-02-27 14:31:35 +0000663 // No need to save live registers; it's taken care of by the
664 // entrypoint. Also, there is no need to update the stack mask,
665 // as this runtime call will not trigger a garbage collection.
666 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
667 DCHECK_NE(ref_reg, SP);
668 DCHECK_NE(ref_reg, LR);
669 DCHECK_NE(ref_reg, PC);
670 // IP is used internally by the ReadBarrierMarkRegX entry point
671 // as a temporary, it cannot be the entry point's input/output.
672 DCHECK_NE(ref_reg, IP);
673 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCoreRegisters) << ref_reg;
674 // "Compact" slow path, saving two moves.
675 //
676 // Instead of using the standard runtime calling convention (input
677 // and output in R0):
678 //
679 // R0 <- ref
680 // R0 <- ReadBarrierMark(R0)
681 // ref <- R0
682 //
683 // we just use rX (the register containing `ref`) as input and output
684 // of a dedicated entrypoint:
685 //
686 // rX <- ReadBarrierMarkRegX(rX)
687 //
688 if (entrypoint_.IsValid()) {
689 arm_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
690 __ blx(entrypoint_.AsRegister<Register>());
691 } else {
Roland Levillain54f869e2017-03-06 13:54:11 +0000692 // Entrypoint is not already loaded, load from the thread.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000693 int32_t entry_point_offset =
694 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref_reg);
695 // This runtime call does not require a stack map.
696 arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
697 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000698 }
699
700 // The location (register) of the marked object reference.
701 const Location ref_;
702
703 // The location of the entrypoint if it is already loaded.
704 const Location entrypoint_;
705
706 private:
707 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathBaseARM);
708};
709
Dave Allison20dfc792014-06-16 20:44:29 -0700710// Slow path marking an object reference `ref` during a read
711// barrier. The field `obj.field` in the object `obj` holding this
Roland Levillain54f869e2017-03-06 13:54:11 +0000712// reference does not get updated by this slow path after marking.
Dave Allison20dfc792014-06-16 20:44:29 -0700713//
714// This means that after the execution of this slow path, `ref` will
715// always be up-to-date, but `obj.field` may not; i.e., after the
716// flip, `ref` will be a to-space reference, but `obj.field` will
717// probably still be a from-space reference (unless it gets updated by
718// another thread, or if another thread installed another object
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000719// reference (different from `ref`) in `obj.field`).
720//
721// If `entrypoint` is a valid location it is assumed to already be
722// holding the entrypoint. The case where the entrypoint is passed in
Roland Levillainba650a42017-03-06 13:52:32 +0000723// is when the decision to mark is based on whether the GC is marking.
Roland Levillain54f869e2017-03-06 13:54:11 +0000724class ReadBarrierMarkSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000725 public:
726 ReadBarrierMarkSlowPathARM(HInstruction* instruction,
727 Location ref,
728 Location entrypoint = Location::NoLocation())
Roland Levillain54f869e2017-03-06 13:54:11 +0000729 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000730 DCHECK(kEmitCompilerReadBarrier);
731 }
732
733 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
734
735 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
736 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain54f869e2017-03-06 13:54:11 +0000737 DCHECK(locations->CanCall());
738 if (kIsDebugBuild) {
739 Register ref_reg = ref_.AsRegister<Register>();
740 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
741 }
742 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
743 << "Unexpected instruction in read barrier marking slow path: "
744 << instruction_->DebugName();
745
746 __ Bind(GetEntryLabel());
747 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000748 __ b(GetExitLabel());
749 }
750
751 private:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000752 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
753};
754
Roland Levillain54f869e2017-03-06 13:54:11 +0000755// Slow path loading `obj`'s lock word, loading a reference from
756// object `*(obj + offset + (index << scale_factor))` into `ref`, and
757// marking `ref` if `obj` is gray according to the lock word (Baker
758// read barrier). The field `obj.field` in the object `obj` holding
759// this reference does not get updated by this slow path after marking
760// (see LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
761// below for that).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000762//
Roland Levillain54f869e2017-03-06 13:54:11 +0000763// This means that after the execution of this slow path, `ref` will
764// always be up-to-date, but `obj.field` may not; i.e., after the
765// flip, `ref` will be a to-space reference, but `obj.field` will
766// probably still be a from-space reference (unless it gets updated by
767// another thread, or if another thread installed another object
768// reference (different from `ref`) in `obj.field`).
769//
770// Argument `entrypoint` must be a register location holding the read
771// barrier marking runtime entry point to be invoked.
772class LoadReferenceWithBakerReadBarrierSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000773 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000774 LoadReferenceWithBakerReadBarrierSlowPathARM(HInstruction* instruction,
775 Location ref,
776 Register obj,
777 uint32_t offset,
778 Location index,
779 ScaleFactor scale_factor,
780 bool needs_null_check,
781 Register temp,
782 Location entrypoint)
783 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000784 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000785 offset_(offset),
786 index_(index),
787 scale_factor_(scale_factor),
788 needs_null_check_(needs_null_check),
789 temp_(temp) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000790 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000791 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000792 }
793
Roland Levillain54f869e2017-03-06 13:54:11 +0000794 const char* GetDescription() const OVERRIDE {
795 return "LoadReferenceWithBakerReadBarrierSlowPathARM";
796 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000797
798 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
799 LocationSummary* locations = instruction_->GetLocations();
800 Register ref_reg = ref_.AsRegister<Register>();
801 DCHECK(locations->CanCall());
802 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000803 DCHECK_NE(ref_reg, temp_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000804 DCHECK(instruction_->IsInstanceFieldGet() ||
805 instruction_->IsStaticFieldGet() ||
806 instruction_->IsArrayGet() ||
807 instruction_->IsArraySet() ||
Roland Levillain47b3ab22017-02-27 14:31:35 +0000808 instruction_->IsInstanceOf() ||
809 instruction_->IsCheckCast() ||
810 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
811 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
812 << "Unexpected instruction in read barrier marking slow path: "
813 << instruction_->DebugName();
814 // The read barrier instrumentation of object ArrayGet
815 // instructions does not support the HIntermediateAddress
816 // instruction.
817 DCHECK(!(instruction_->IsArrayGet() &&
818 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
819
820 __ Bind(GetEntryLabel());
Roland Levillain54f869e2017-03-06 13:54:11 +0000821
822 // When using MaybeGenerateReadBarrierSlow, the read barrier call is
823 // inserted after the original load. However, in fast path based
824 // Baker's read barriers, we need to perform the load of
825 // mirror::Object::monitor_ *before* the original reference load.
826 // This load-load ordering is required by the read barrier.
827 // The fast path/slow path (for Baker's algorithm) should look like:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000828 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000829 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
830 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
831 // HeapReference<mirror::Object> ref = *src; // Original reference load.
832 // bool is_gray = (rb_state == ReadBarrier::GrayState());
833 // if (is_gray) {
834 // ref = entrypoint(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
835 // }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000836 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000837 // Note: the original implementation in ReadBarrier::Barrier is
838 // slightly more complex as it performs additional checks that we do
839 // not do here for performance reasons.
840
841 // /* int32_t */ monitor = obj->monitor_
842 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
843 __ LoadFromOffset(kLoadWord, temp_, obj_, monitor_offset);
844 if (needs_null_check_) {
845 codegen->MaybeRecordImplicitNullCheck(instruction_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000846 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000847 // /* LockWord */ lock_word = LockWord(monitor)
848 static_assert(sizeof(LockWord) == sizeof(int32_t),
849 "art::LockWord and int32_t have different sizes.");
850
851 // Introduce a dependency on the lock_word including the rb_state,
852 // which shall prevent load-load reordering without using
853 // a memory barrier (which would be more expensive).
854 // `obj` is unchanged by this operation, but its value now depends
855 // on `temp`.
856 __ add(obj_, obj_, ShifterOperand(temp_, LSR, 32));
857
858 // The actual reference load.
859 // A possible implicit null check has already been handled above.
860 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
861 arm_codegen->GenerateRawReferenceLoad(
862 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
863
864 // Mark the object `ref` when `obj` is gray.
865 //
866 // if (rb_state == ReadBarrier::GrayState())
867 // ref = ReadBarrier::Mark(ref);
868 //
869 // Given the numeric representation, it's enough to check the low bit of the
870 // rb_state. We do that by shifting the bit out of the lock word with LSRS
871 // which can be a 16-bit instruction unlike the TST immediate.
872 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
873 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
874 __ Lsrs(temp_, temp_, LockWord::kReadBarrierStateShift + 1);
875 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
876 GenerateReadBarrierMarkRuntimeCall(codegen);
877
Roland Levillain47b3ab22017-02-27 14:31:35 +0000878 __ b(GetExitLabel());
879 }
880
881 private:
Roland Levillain54f869e2017-03-06 13:54:11 +0000882 // The register containing the object holding the marked object reference field.
883 Register obj_;
884 // The offset, index and scale factor to access the reference in `obj_`.
885 uint32_t offset_;
886 Location index_;
887 ScaleFactor scale_factor_;
888 // Is a null check required?
889 bool needs_null_check_;
890 // A temporary register used to hold the lock word of `obj_`.
891 Register temp_;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000892
Roland Levillain54f869e2017-03-06 13:54:11 +0000893 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierSlowPathARM);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000894};
895
Roland Levillain54f869e2017-03-06 13:54:11 +0000896// Slow path loading `obj`'s lock word, loading a reference from
897// object `*(obj + offset + (index << scale_factor))` into `ref`, and
898// marking `ref` if `obj` is gray according to the lock word (Baker
899// read barrier). If needed, this slow path also atomically updates
900// the field `obj.field` in the object `obj` holding this reference
901// after marking (contrary to
902// LoadReferenceWithBakerReadBarrierSlowPathARM above, which never
903// tries to update `obj.field`).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000904//
905// This means that after the execution of this slow path, both `ref`
906// and `obj.field` will be up-to-date; i.e., after the flip, both will
907// hold the same to-space reference (unless another thread installed
908// another object reference (different from `ref`) in `obj.field`).
Roland Levillainba650a42017-03-06 13:52:32 +0000909//
Roland Levillain54f869e2017-03-06 13:54:11 +0000910// Argument `entrypoint` must be a register location holding the read
911// barrier marking runtime entry point to be invoked.
912class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
913 : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000914 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000915 LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(HInstruction* instruction,
916 Location ref,
917 Register obj,
918 uint32_t offset,
919 Location index,
920 ScaleFactor scale_factor,
921 bool needs_null_check,
922 Register temp1,
923 Register temp2,
924 Location entrypoint)
925 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000926 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000927 offset_(offset),
928 index_(index),
929 scale_factor_(scale_factor),
930 needs_null_check_(needs_null_check),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000931 temp1_(temp1),
Roland Levillain54f869e2017-03-06 13:54:11 +0000932 temp2_(temp2) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000933 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000934 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000935 }
936
Roland Levillain54f869e2017-03-06 13:54:11 +0000937 const char* GetDescription() const OVERRIDE {
938 return "LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM";
939 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000940
941 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
942 LocationSummary* locations = instruction_->GetLocations();
943 Register ref_reg = ref_.AsRegister<Register>();
944 DCHECK(locations->CanCall());
945 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000946 DCHECK_NE(ref_reg, temp1_);
947
948 // This slow path is only used by the UnsafeCASObject intrinsic at the moment.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000949 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
950 << "Unexpected instruction in read barrier marking and field updating slow path: "
951 << instruction_->DebugName();
952 DCHECK(instruction_->GetLocations()->Intrinsified());
953 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
Roland Levillain54f869e2017-03-06 13:54:11 +0000954 DCHECK_EQ(offset_, 0u);
955 DCHECK_EQ(scale_factor_, ScaleFactor::TIMES_1);
956 // The location of the offset of the marked reference field within `obj_`.
957 Location field_offset = index_;
958 DCHECK(field_offset.IsRegisterPair()) << field_offset;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000959
960 __ Bind(GetEntryLabel());
961
Roland Levillain54f869e2017-03-06 13:54:11 +0000962 // /* int32_t */ monitor = obj->monitor_
963 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
964 __ LoadFromOffset(kLoadWord, temp1_, obj_, monitor_offset);
965 if (needs_null_check_) {
966 codegen->MaybeRecordImplicitNullCheck(instruction_);
967 }
968 // /* LockWord */ lock_word = LockWord(monitor)
969 static_assert(sizeof(LockWord) == sizeof(int32_t),
970 "art::LockWord and int32_t have different sizes.");
971
972 // Introduce a dependency on the lock_word including the rb_state,
973 // which shall prevent load-load reordering without using
974 // a memory barrier (which would be more expensive).
975 // `obj` is unchanged by this operation, but its value now depends
976 // on `temp1`.
977 __ add(obj_, obj_, ShifterOperand(temp1_, LSR, 32));
978
979 // The actual reference load.
980 // A possible implicit null check has already been handled above.
981 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
982 arm_codegen->GenerateRawReferenceLoad(
983 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
984
985 // Mark the object `ref` when `obj` is gray.
986 //
987 // if (rb_state == ReadBarrier::GrayState())
988 // ref = ReadBarrier::Mark(ref);
989 //
990 // Given the numeric representation, it's enough to check the low bit of the
991 // rb_state. We do that by shifting the bit out of the lock word with LSRS
992 // which can be a 16-bit instruction unlike the TST immediate.
993 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
994 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
995 __ Lsrs(temp1_, temp1_, LockWord::kReadBarrierStateShift + 1);
996 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
997
998 // Save the old value of the reference before marking it.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000999 // Note that we cannot use IP to save the old reference, as IP is
1000 // used internally by the ReadBarrierMarkRegX entry point, and we
1001 // need the old reference after the call to that entry point.
1002 DCHECK_NE(temp1_, IP);
1003 __ Mov(temp1_, ref_reg);
Roland Levillain27b1f9c2017-01-17 16:56:34 +00001004
Roland Levillain54f869e2017-03-06 13:54:11 +00001005 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001006
1007 // If the new reference is different from the old reference,
Roland Levillain54f869e2017-03-06 13:54:11 +00001008 // update the field in the holder (`*(obj_ + field_offset)`).
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001009 //
1010 // Note that this field could also hold a different object, if
1011 // another thread had concurrently changed it. In that case, the
1012 // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set
1013 // (CAS) operation below would abort the CAS, leaving the field
1014 // as-is.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001015 __ cmp(temp1_, ShifterOperand(ref_reg));
Roland Levillain54f869e2017-03-06 13:54:11 +00001016 __ b(GetExitLabel(), EQ);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001017
1018 // Update the the holder's field atomically. This may fail if
1019 // mutator updates before us, but it's OK. This is achieved
1020 // using a strong compare-and-set (CAS) operation with relaxed
1021 // memory synchronization ordering, where the expected value is
1022 // the old reference and the desired value is the new reference.
1023
1024 // Convenience aliases.
1025 Register base = obj_;
1026 // The UnsafeCASObject intrinsic uses a register pair as field
1027 // offset ("long offset"), of which only the low part contains
1028 // data.
Roland Levillain54f869e2017-03-06 13:54:11 +00001029 Register offset = field_offset.AsRegisterPairLow<Register>();
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001030 Register expected = temp1_;
1031 Register value = ref_reg;
1032 Register tmp_ptr = IP; // Pointer to actual memory.
1033 Register tmp = temp2_; // Value in memory.
1034
1035 __ add(tmp_ptr, base, ShifterOperand(offset));
1036
1037 if (kPoisonHeapReferences) {
1038 __ PoisonHeapReference(expected);
1039 if (value == expected) {
1040 // Do not poison `value`, as it is the same register as
1041 // `expected`, which has just been poisoned.
1042 } else {
1043 __ PoisonHeapReference(value);
1044 }
1045 }
1046
1047 // do {
1048 // tmp = [r_ptr] - expected;
1049 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
1050
Roland Levillain24a4d112016-10-26 13:10:46 +01001051 Label loop_head, exit_loop;
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001052 __ Bind(&loop_head);
1053
1054 __ ldrex(tmp, tmp_ptr);
1055
1056 __ subs(tmp, tmp, ShifterOperand(expected));
1057
Roland Levillain24a4d112016-10-26 13:10:46 +01001058 __ it(NE);
1059 __ clrex(NE);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001060
Roland Levillain24a4d112016-10-26 13:10:46 +01001061 __ b(&exit_loop, NE);
1062
1063 __ strex(tmp, value, tmp_ptr);
1064 __ cmp(tmp, ShifterOperand(1));
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001065 __ b(&loop_head, EQ);
1066
Roland Levillain24a4d112016-10-26 13:10:46 +01001067 __ Bind(&exit_loop);
1068
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001069 if (kPoisonHeapReferences) {
1070 __ UnpoisonHeapReference(expected);
1071 if (value == expected) {
1072 // Do not unpoison `value`, as it is the same register as
1073 // `expected`, which has just been unpoisoned.
1074 } else {
1075 __ UnpoisonHeapReference(value);
1076 }
1077 }
1078
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001079 __ b(GetExitLabel());
1080 }
1081
1082 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001083 // The register containing the object holding the marked object reference field.
1084 const Register obj_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001085 // The offset, index and scale factor to access the reference in `obj_`.
1086 uint32_t offset_;
1087 Location index_;
1088 ScaleFactor scale_factor_;
1089 // Is a null check required?
1090 bool needs_null_check_;
1091 // A temporary register used to hold the lock word of `obj_`; and
1092 // also to hold the original reference value, when the reference is
1093 // marked.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001094 const Register temp1_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001095 // A temporary register used in the implementation of the CAS, to
1096 // update the object's reference field.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001097 const Register temp2_;
1098
Roland Levillain54f869e2017-03-06 13:54:11 +00001099 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001100};
1101
Roland Levillain3b359c72015-11-17 19:35:12 +00001102// Slow path generating a read barrier for a heap reference.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001103class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001104 public:
1105 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
1106 Location out,
1107 Location ref,
1108 Location obj,
1109 uint32_t offset,
1110 Location index)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001111 : SlowPathCodeARM(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +00001112 out_(out),
1113 ref_(ref),
1114 obj_(obj),
1115 offset_(offset),
1116 index_(index) {
1117 DCHECK(kEmitCompilerReadBarrier);
1118 // If `obj` is equal to `out` or `ref`, it means the initial object
1119 // has been overwritten by (or after) the heap object reference load
1120 // to be instrumented, e.g.:
1121 //
1122 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00001123 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001124 //
1125 // In that case, we have lost the information about the original
1126 // object, and the emitted read barrier cannot work properly.
1127 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
1128 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
1129 }
1130
1131 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1132 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1133 LocationSummary* locations = instruction_->GetLocations();
1134 Register reg_out = out_.AsRegister<Register>();
1135 DCHECK(locations->CanCall());
1136 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +01001137 DCHECK(instruction_->IsInstanceFieldGet() ||
1138 instruction_->IsStaticFieldGet() ||
1139 instruction_->IsArrayGet() ||
1140 instruction_->IsInstanceOf() ||
1141 instruction_->IsCheckCast() ||
Andreas Gamped9911ee2017-03-27 13:27:24 -07001142 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
Roland Levillainc9285912015-12-18 10:38:42 +00001143 << "Unexpected instruction in read barrier for heap reference slow path: "
1144 << instruction_->DebugName();
Roland Levillain19c54192016-11-04 13:44:09 +00001145 // The read barrier instrumentation of object ArrayGet
1146 // instructions does not support the HIntermediateAddress
1147 // instruction.
1148 DCHECK(!(instruction_->IsArrayGet() &&
1149 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
Roland Levillain3b359c72015-11-17 19:35:12 +00001150
1151 __ Bind(GetEntryLabel());
1152 SaveLiveRegisters(codegen, locations);
1153
1154 // We may have to change the index's value, but as `index_` is a
1155 // constant member (like other "inputs" of this slow path),
1156 // introduce a copy of it, `index`.
1157 Location index = index_;
1158 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +01001159 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +00001160 if (instruction_->IsArrayGet()) {
1161 // Compute the actual memory offset and store it in `index`.
1162 Register index_reg = index_.AsRegister<Register>();
1163 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
1164 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
1165 // We are about to change the value of `index_reg` (see the
1166 // calls to art::arm::Thumb2Assembler::Lsl and
1167 // art::arm::Thumb2Assembler::AddConstant below), but it has
1168 // not been saved by the previous call to
1169 // art::SlowPathCode::SaveLiveRegisters, as it is a
1170 // callee-save register --
1171 // art::SlowPathCode::SaveLiveRegisters does not consider
1172 // callee-save registers, as it has been designed with the
1173 // assumption that callee-save registers are supposed to be
1174 // handled by the called function. So, as a callee-save
1175 // register, `index_reg` _would_ eventually be saved onto
1176 // the stack, but it would be too late: we would have
1177 // changed its value earlier. Therefore, we manually save
1178 // it here into another freely available register,
1179 // `free_reg`, chosen of course among the caller-save
1180 // registers (as a callee-save `free_reg` register would
1181 // exhibit the same problem).
1182 //
1183 // Note we could have requested a temporary register from
1184 // the register allocator instead; but we prefer not to, as
1185 // this is a slow path, and we know we can find a
1186 // caller-save register that is available.
1187 Register free_reg = FindAvailableCallerSaveRegister(codegen);
1188 __ Mov(free_reg, index_reg);
1189 index_reg = free_reg;
1190 index = Location::RegisterLocation(index_reg);
1191 } else {
1192 // The initial register stored in `index_` has already been
1193 // saved in the call to art::SlowPathCode::SaveLiveRegisters
1194 // (as it is not a callee-save register), so we can freely
1195 // use it.
1196 }
1197 // Shifting the index value contained in `index_reg` by the scale
1198 // factor (2) cannot overflow in practice, as the runtime is
1199 // unable to allocate object arrays with a size larger than
1200 // 2^26 - 1 (that is, 2^28 - 4 bytes).
1201 __ Lsl(index_reg, index_reg, TIMES_4);
1202 static_assert(
1203 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
1204 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
1205 __ AddConstant(index_reg, index_reg, offset_);
1206 } else {
Roland Levillain3d312422016-06-23 13:53:42 +01001207 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
1208 // intrinsics, `index_` is not shifted by a scale factor of 2
1209 // (as in the case of ArrayGet), as it is actually an offset
1210 // to an object field within an object.
1211 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001212 DCHECK(instruction_->GetLocations()->Intrinsified());
1213 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
1214 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
1215 << instruction_->AsInvoke()->GetIntrinsic();
1216 DCHECK_EQ(offset_, 0U);
1217 DCHECK(index_.IsRegisterPair());
1218 // UnsafeGet's offset location is a register pair, the low
1219 // part contains the correct offset.
1220 index = index_.ToLow();
1221 }
1222 }
1223
1224 // We're moving two or three locations to locations that could
1225 // overlap, so we need a parallel move resolver.
1226 InvokeRuntimeCallingConvention calling_convention;
1227 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
1228 parallel_move.AddMove(ref_,
1229 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
1230 Primitive::kPrimNot,
1231 nullptr);
1232 parallel_move.AddMove(obj_,
1233 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
1234 Primitive::kPrimNot,
1235 nullptr);
1236 if (index.IsValid()) {
1237 parallel_move.AddMove(index,
1238 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
1239 Primitive::kPrimInt,
1240 nullptr);
1241 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1242 } else {
1243 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1244 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
1245 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001246 arm_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
Roland Levillain3b359c72015-11-17 19:35:12 +00001247 CheckEntrypointTypes<
1248 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
1249 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1250
1251 RestoreLiveRegisters(codegen, locations);
1252 __ b(GetExitLabel());
1253 }
1254
1255 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
1256
1257 private:
1258 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
1259 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
1260 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
1261 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
1262 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
1263 return static_cast<Register>(i);
1264 }
1265 }
1266 // We shall never fail to find a free caller-save register, as
1267 // there are more than two core caller-save registers on ARM
1268 // (meaning it is possible to find one which is different from
1269 // `ref` and `obj`).
1270 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
1271 LOG(FATAL) << "Could not find a free caller-save register";
1272 UNREACHABLE();
1273 }
1274
Roland Levillain3b359c72015-11-17 19:35:12 +00001275 const Location out_;
1276 const Location ref_;
1277 const Location obj_;
1278 const uint32_t offset_;
1279 // An additional location containing an index to an array.
1280 // Only used for HArrayGet and the UnsafeGetObject &
1281 // UnsafeGetObjectVolatile intrinsics.
1282 const Location index_;
1283
1284 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
1285};
1286
1287// Slow path generating a read barrier for a GC root.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001288class ReadBarrierForRootSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001289 public:
1290 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001291 : SlowPathCodeARM(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +00001292 DCHECK(kEmitCompilerReadBarrier);
1293 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001294
1295 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1296 LocationSummary* locations = instruction_->GetLocations();
1297 Register reg_out = out_.AsRegister<Register>();
1298 DCHECK(locations->CanCall());
1299 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +00001300 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
1301 << "Unexpected instruction in read barrier for GC root slow path: "
1302 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001303
1304 __ Bind(GetEntryLabel());
1305 SaveLiveRegisters(codegen, locations);
1306
1307 InvokeRuntimeCallingConvention calling_convention;
1308 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1309 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001310 arm_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain3b359c72015-11-17 19:35:12 +00001311 instruction_,
1312 instruction_->GetDexPc(),
1313 this);
1314 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
1315 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1316
1317 RestoreLiveRegisters(codegen, locations);
1318 __ b(GetExitLabel());
1319 }
1320
1321 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
1322
1323 private:
Roland Levillain3b359c72015-11-17 19:35:12 +00001324 const Location out_;
1325 const Location root_;
1326
1327 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
1328};
1329
Aart Bike9f37602015-10-09 11:15:55 -07001330inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001331 switch (cond) {
1332 case kCondEQ: return EQ;
1333 case kCondNE: return NE;
1334 case kCondLT: return LT;
1335 case kCondLE: return LE;
1336 case kCondGT: return GT;
1337 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -07001338 case kCondB: return LO;
1339 case kCondBE: return LS;
1340 case kCondA: return HI;
1341 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001342 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001343 LOG(FATAL) << "Unreachable";
1344 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001345}
1346
Aart Bike9f37602015-10-09 11:15:55 -07001347// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001348inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001349 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001350 case kCondEQ: return EQ;
1351 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -07001352 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001353 case kCondLT: return LO;
1354 case kCondLE: return LS;
1355 case kCondGT: return HI;
1356 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -07001357 // Unsigned remain unchanged.
1358 case kCondB: return LO;
1359 case kCondBE: return LS;
1360 case kCondA: return HI;
1361 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001362 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001363 LOG(FATAL) << "Unreachable";
1364 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001365}
1366
Vladimir Markod6e069b2016-01-18 11:11:01 +00001367inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
1368 // The ARM condition codes can express all the necessary branches, see the
1369 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
1370 // There is no dex instruction or HIR that would need the missing conditions
1371 // "equal or unordered" or "not equal".
1372 switch (cond) {
1373 case kCondEQ: return EQ;
1374 case kCondNE: return NE /* unordered */;
1375 case kCondLT: return gt_bias ? CC : LT /* unordered */;
1376 case kCondLE: return gt_bias ? LS : LE /* unordered */;
1377 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
1378 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
1379 default:
1380 LOG(FATAL) << "UNREACHABLE";
1381 UNREACHABLE();
1382 }
1383}
1384
Anton Kirilov74234da2017-01-13 14:42:47 +00001385inline Shift ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
1386 switch (op_kind) {
1387 case HDataProcWithShifterOp::kASR: return ASR;
1388 case HDataProcWithShifterOp::kLSL: return LSL;
1389 case HDataProcWithShifterOp::kLSR: return LSR;
1390 default:
1391 LOG(FATAL) << "Unexpected op kind " << op_kind;
1392 UNREACHABLE();
1393 }
1394}
1395
1396static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
1397 Register out,
1398 Register first,
1399 const ShifterOperand& second,
1400 CodeGeneratorARM* codegen) {
1401 if (second.IsImmediate() && second.GetImmediate() == 0) {
1402 const ShifterOperand in = kind == HInstruction::kAnd
1403 ? ShifterOperand(0)
1404 : ShifterOperand(first);
1405
1406 __ mov(out, in);
1407 } else {
1408 switch (kind) {
1409 case HInstruction::kAdd:
1410 __ add(out, first, second);
1411 break;
1412 case HInstruction::kAnd:
1413 __ and_(out, first, second);
1414 break;
1415 case HInstruction::kOr:
1416 __ orr(out, first, second);
1417 break;
1418 case HInstruction::kSub:
1419 __ sub(out, first, second);
1420 break;
1421 case HInstruction::kXor:
1422 __ eor(out, first, second);
1423 break;
1424 default:
1425 LOG(FATAL) << "Unexpected instruction kind: " << kind;
1426 UNREACHABLE();
1427 }
1428 }
1429}
1430
1431static void GenerateDataProc(HInstruction::InstructionKind kind,
1432 const Location& out,
1433 const Location& first,
1434 const ShifterOperand& second_lo,
1435 const ShifterOperand& second_hi,
1436 CodeGeneratorARM* codegen) {
1437 const Register first_hi = first.AsRegisterPairHigh<Register>();
1438 const Register first_lo = first.AsRegisterPairLow<Register>();
1439 const Register out_hi = out.AsRegisterPairHigh<Register>();
1440 const Register out_lo = out.AsRegisterPairLow<Register>();
1441
1442 if (kind == HInstruction::kAdd) {
1443 __ adds(out_lo, first_lo, second_lo);
1444 __ adc(out_hi, first_hi, second_hi);
1445 } else if (kind == HInstruction::kSub) {
1446 __ subs(out_lo, first_lo, second_lo);
1447 __ sbc(out_hi, first_hi, second_hi);
1448 } else {
1449 GenerateDataProcInstruction(kind, out_lo, first_lo, second_lo, codegen);
1450 GenerateDataProcInstruction(kind, out_hi, first_hi, second_hi, codegen);
1451 }
1452}
1453
1454static ShifterOperand GetShifterOperand(Register rm, Shift shift, uint32_t shift_imm) {
1455 return shift_imm == 0 ? ShifterOperand(rm) : ShifterOperand(rm, shift, shift_imm);
1456}
1457
1458static void GenerateLongDataProc(HDataProcWithShifterOp* instruction, CodeGeneratorARM* codegen) {
1459 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
1460 DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
1461
1462 const LocationSummary* const locations = instruction->GetLocations();
1463 const uint32_t shift_value = instruction->GetShiftAmount();
1464 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
1465 const Location first = locations->InAt(0);
1466 const Location second = locations->InAt(1);
1467 const Location out = locations->Out();
1468 const Register first_hi = first.AsRegisterPairHigh<Register>();
1469 const Register first_lo = first.AsRegisterPairLow<Register>();
1470 const Register out_hi = out.AsRegisterPairHigh<Register>();
1471 const Register out_lo = out.AsRegisterPairLow<Register>();
1472 const Register second_hi = second.AsRegisterPairHigh<Register>();
1473 const Register second_lo = second.AsRegisterPairLow<Register>();
1474 const Shift shift = ShiftFromOpKind(instruction->GetOpKind());
1475
1476 if (shift_value >= 32) {
1477 if (shift == LSL) {
1478 GenerateDataProcInstruction(kind,
1479 out_hi,
1480 first_hi,
1481 ShifterOperand(second_lo, LSL, shift_value - 32),
1482 codegen);
1483 GenerateDataProcInstruction(kind,
1484 out_lo,
1485 first_lo,
1486 ShifterOperand(0),
1487 codegen);
1488 } else if (shift == ASR) {
1489 GenerateDataProc(kind,
1490 out,
1491 first,
1492 GetShifterOperand(second_hi, ASR, shift_value - 32),
1493 ShifterOperand(second_hi, ASR, 31),
1494 codegen);
1495 } else {
1496 DCHECK_EQ(shift, LSR);
1497 GenerateDataProc(kind,
1498 out,
1499 first,
1500 GetShifterOperand(second_hi, LSR, shift_value - 32),
1501 ShifterOperand(0),
1502 codegen);
1503 }
1504 } else {
1505 DCHECK_GT(shift_value, 1U);
1506 DCHECK_LT(shift_value, 32U);
1507
1508 if (shift == LSL) {
1509 // We are not doing this for HInstruction::kAdd because the output will require
1510 // Location::kOutputOverlap; not applicable to other cases.
1511 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1512 GenerateDataProcInstruction(kind,
1513 out_hi,
1514 first_hi,
1515 ShifterOperand(second_hi, LSL, shift_value),
1516 codegen);
1517 GenerateDataProcInstruction(kind,
1518 out_hi,
1519 out_hi,
1520 ShifterOperand(second_lo, LSR, 32 - shift_value),
1521 codegen);
1522 GenerateDataProcInstruction(kind,
1523 out_lo,
1524 first_lo,
1525 ShifterOperand(second_lo, LSL, shift_value),
1526 codegen);
1527 } else {
1528 __ Lsl(IP, second_hi, shift_value);
1529 __ orr(IP, IP, ShifterOperand(second_lo, LSR, 32 - shift_value));
1530 GenerateDataProc(kind,
1531 out,
1532 first,
1533 ShifterOperand(second_lo, LSL, shift_value),
1534 ShifterOperand(IP),
1535 codegen);
1536 }
1537 } else {
1538 DCHECK(shift == ASR || shift == LSR);
1539
1540 // We are not doing this for HInstruction::kAdd because the output will require
1541 // Location::kOutputOverlap; not applicable to other cases.
1542 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1543 GenerateDataProcInstruction(kind,
1544 out_lo,
1545 first_lo,
1546 ShifterOperand(second_lo, LSR, shift_value),
1547 codegen);
1548 GenerateDataProcInstruction(kind,
1549 out_lo,
1550 out_lo,
1551 ShifterOperand(second_hi, LSL, 32 - shift_value),
1552 codegen);
1553 GenerateDataProcInstruction(kind,
1554 out_hi,
1555 first_hi,
1556 ShifterOperand(second_hi, shift, shift_value),
1557 codegen);
1558 } else {
1559 __ Lsr(IP, second_lo, shift_value);
1560 __ orr(IP, IP, ShifterOperand(second_hi, LSL, 32 - shift_value));
1561 GenerateDataProc(kind,
1562 out,
1563 first,
1564 ShifterOperand(IP),
1565 ShifterOperand(second_hi, shift, shift_value),
1566 codegen);
1567 }
1568 }
1569 }
1570}
1571
Donghui Bai426b49c2016-11-08 14:55:38 +08001572static void GenerateVcmp(HInstruction* instruction, CodeGeneratorARM* codegen) {
1573 Primitive::Type type = instruction->InputAt(0)->GetType();
1574 Location lhs_loc = instruction->GetLocations()->InAt(0);
1575 Location rhs_loc = instruction->GetLocations()->InAt(1);
1576 if (rhs_loc.IsConstant()) {
1577 // 0.0 is the only immediate that can be encoded directly in
1578 // a VCMP instruction.
1579 //
1580 // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
1581 // specify that in a floating-point comparison, positive zero
1582 // and negative zero are considered equal, so we can use the
1583 // literal 0.0 for both cases here.
1584 //
1585 // Note however that some methods (Float.equal, Float.compare,
1586 // Float.compareTo, Double.equal, Double.compare,
1587 // Double.compareTo, Math.max, Math.min, StrictMath.max,
1588 // StrictMath.min) consider 0.0 to be (strictly) greater than
1589 // -0.0. So if we ever translate calls to these methods into a
1590 // HCompare instruction, we must handle the -0.0 case with
1591 // care here.
1592 DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
1593 if (type == Primitive::kPrimFloat) {
1594 __ vcmpsz(lhs_loc.AsFpuRegister<SRegister>());
1595 } else {
1596 DCHECK_EQ(type, Primitive::kPrimDouble);
1597 __ vcmpdz(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()));
1598 }
1599 } else {
1600 if (type == Primitive::kPrimFloat) {
1601 __ vcmps(lhs_loc.AsFpuRegister<SRegister>(), rhs_loc.AsFpuRegister<SRegister>());
1602 } else {
1603 DCHECK_EQ(type, Primitive::kPrimDouble);
1604 __ vcmpd(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()),
1605 FromLowSToD(rhs_loc.AsFpuRegisterPairLow<SRegister>()));
1606 }
1607 }
1608}
1609
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001610static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* condition,
1611 bool invert,
1612 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001613 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1614
1615 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001616 IfCondition cond = condition->GetCondition();
1617 IfCondition opposite = condition->GetOppositeCondition();
1618
1619 if (invert) {
1620 std::swap(cond, opposite);
1621 }
1622
1623 std::pair<Condition, Condition> ret;
Donghui Bai426b49c2016-11-08 14:55:38 +08001624 const Location left = locations->InAt(0);
1625 const Location right = locations->InAt(1);
1626
1627 DCHECK(right.IsConstant());
1628
1629 const Register left_high = left.AsRegisterPairHigh<Register>();
1630 const Register left_low = left.AsRegisterPairLow<Register>();
1631 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
1632
1633 switch (cond) {
1634 case kCondEQ:
1635 case kCondNE:
1636 case kCondB:
1637 case kCondBE:
1638 case kCondA:
1639 case kCondAE:
1640 __ CmpConstant(left_high, High32Bits(value));
1641 __ it(EQ);
1642 __ cmp(left_low, ShifterOperand(Low32Bits(value)), EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001643 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001644 break;
1645 case kCondLE:
1646 case kCondGT:
1647 // Trivially true or false.
1648 if (value == std::numeric_limits<int64_t>::max()) {
1649 __ cmp(left_low, ShifterOperand(left_low));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001650 ret = cond == kCondLE ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
Donghui Bai426b49c2016-11-08 14:55:38 +08001651 break;
1652 }
1653
1654 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001655 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001656 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001657 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001658 } else {
1659 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001660 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001661 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001662 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001663 }
1664
1665 value++;
1666 FALLTHROUGH_INTENDED;
1667 case kCondGE:
1668 case kCondLT:
1669 __ CmpConstant(left_low, Low32Bits(value));
1670 __ sbcs(IP, left_high, ShifterOperand(High32Bits(value)));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001671 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001672 break;
1673 default:
1674 LOG(FATAL) << "Unreachable";
1675 UNREACHABLE();
1676 }
1677
1678 return ret;
1679}
1680
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001681static std::pair<Condition, Condition> GenerateLongTest(HCondition* condition,
1682 bool invert,
1683 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001684 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1685
1686 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001687 IfCondition cond = condition->GetCondition();
1688 IfCondition opposite = condition->GetOppositeCondition();
1689
1690 if (invert) {
1691 std::swap(cond, opposite);
1692 }
1693
1694 std::pair<Condition, Condition> ret;
Donghui Bai426b49c2016-11-08 14:55:38 +08001695 Location left = locations->InAt(0);
1696 Location right = locations->InAt(1);
1697
1698 DCHECK(right.IsRegisterPair());
1699
1700 switch (cond) {
1701 case kCondEQ:
1702 case kCondNE:
1703 case kCondB:
1704 case kCondBE:
1705 case kCondA:
1706 case kCondAE:
1707 __ cmp(left.AsRegisterPairHigh<Register>(),
1708 ShifterOperand(right.AsRegisterPairHigh<Register>()));
1709 __ it(EQ);
1710 __ cmp(left.AsRegisterPairLow<Register>(),
1711 ShifterOperand(right.AsRegisterPairLow<Register>()),
1712 EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001713 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001714 break;
1715 case kCondLE:
1716 case kCondGT:
1717 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001718 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001719 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001720 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001721 } else {
1722 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001723 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001724 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001725 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001726 }
1727
1728 std::swap(left, right);
1729 FALLTHROUGH_INTENDED;
1730 case kCondGE:
1731 case kCondLT:
1732 __ cmp(left.AsRegisterPairLow<Register>(),
1733 ShifterOperand(right.AsRegisterPairLow<Register>()));
1734 __ sbcs(IP,
1735 left.AsRegisterPairHigh<Register>(),
1736 ShifterOperand(right.AsRegisterPairHigh<Register>()));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001737 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001738 break;
1739 default:
1740 LOG(FATAL) << "Unreachable";
1741 UNREACHABLE();
1742 }
1743
1744 return ret;
1745}
1746
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001747static std::pair<Condition, Condition> GenerateTest(HCondition* condition,
1748 bool invert,
1749 CodeGeneratorARM* codegen) {
1750 const LocationSummary* const locations = condition->GetLocations();
1751 const Primitive::Type type = condition->GetLeft()->GetType();
1752 IfCondition cond = condition->GetCondition();
1753 IfCondition opposite = condition->GetOppositeCondition();
1754 std::pair<Condition, Condition> ret;
1755 const Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08001756
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001757 if (invert) {
1758 std::swap(cond, opposite);
1759 }
Donghui Bai426b49c2016-11-08 14:55:38 +08001760
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001761 if (type == Primitive::kPrimLong) {
1762 ret = locations->InAt(1).IsConstant()
1763 ? GenerateLongTestConstant(condition, invert, codegen)
1764 : GenerateLongTest(condition, invert, codegen);
1765 } else if (Primitive::IsFloatingPointType(type)) {
1766 GenerateVcmp(condition, codegen);
1767 __ vmstat();
1768 ret = std::make_pair(ARMFPCondition(cond, condition->IsGtBias()),
1769 ARMFPCondition(opposite, condition->IsGtBias()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001770 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001771 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
Donghui Bai426b49c2016-11-08 14:55:38 +08001772
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001773 const Register left = locations->InAt(0).AsRegister<Register>();
1774
1775 if (right.IsRegister()) {
1776 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001777 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001778 DCHECK(right.IsConstant());
1779 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001780 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001781
1782 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001783 }
1784
1785 return ret;
1786}
1787
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001788static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) {
1789 if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
1790 const LocationSummary* const locations = condition->GetLocations();
1791 const IfCondition c = condition->GetCondition();
Donghui Bai426b49c2016-11-08 14:55:38 +08001792
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001793 if (locations->InAt(1).IsConstant()) {
1794 const int64_t value = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue();
1795 ShifterOperand so;
Donghui Bai426b49c2016-11-08 14:55:38 +08001796
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001797 if (c < kCondLT || c > kCondGE) {
1798 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1799 // we check that the least significant half of the first input to be compared
1800 // is in a low register (the other half is read outside an IT block), and
1801 // the constant fits in an 8-bit unsigned integer, so that a 16-bit CMP
1802 // encoding can be used.
1803 if (!ArmAssembler::IsLowRegister(locations->InAt(0).AsRegisterPairLow<Register>()) ||
1804 !IsUint<8>(Low32Bits(value))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001805 return false;
1806 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001807 } else if (c == kCondLE || c == kCondGT) {
1808 if (value < std::numeric_limits<int64_t>::max() &&
1809 !assembler->ShifterOperandCanHold(kNoRegister,
1810 kNoRegister,
1811 SBC,
1812 High32Bits(value + 1),
1813 kCcSet,
1814 &so)) {
1815 return false;
1816 }
1817 } else if (!assembler->ShifterOperandCanHold(kNoRegister,
1818 kNoRegister,
1819 SBC,
1820 High32Bits(value),
1821 kCcSet,
1822 &so)) {
1823 return false;
Donghui Bai426b49c2016-11-08 14:55:38 +08001824 }
1825 }
1826 }
1827
1828 return true;
1829}
1830
1831static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) {
1832 const Primitive::Type type = constant->GetType();
1833 bool ret = false;
1834
1835 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
1836
1837 if (type == Primitive::kPrimLong) {
1838 const uint64_t value = constant->AsLongConstant()->GetValueAsUint64();
1839
1840 ret = IsUint<8>(Low32Bits(value)) && IsUint<8>(High32Bits(value));
1841 } else {
1842 ret = IsUint<8>(CodeGenerator::GetInt32ValueOf(constant));
1843 }
1844
1845 return ret;
1846}
1847
1848static Location Arm8BitEncodableConstantOrRegister(HInstruction* constant) {
1849 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
1850
1851 if (constant->IsConstant() && CanEncodeConstantAs8BitImmediate(constant->AsConstant())) {
1852 return Location::ConstantLocation(constant->AsConstant());
1853 }
1854
1855 return Location::RequiresRegister();
1856}
1857
1858static bool CanGenerateConditionalMove(const Location& out, const Location& src) {
1859 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1860 // we check that we are not dealing with floating-point output (there is no
1861 // 16-bit VMOV encoding).
1862 if (!out.IsRegister() && !out.IsRegisterPair()) {
1863 return false;
1864 }
1865
1866 // For constants, we also check that the output is in one or two low registers,
1867 // and that the constants fit in an 8-bit unsigned integer, so that a 16-bit
1868 // MOV encoding can be used.
1869 if (src.IsConstant()) {
1870 if (!CanEncodeConstantAs8BitImmediate(src.GetConstant())) {
1871 return false;
1872 }
1873
1874 if (out.IsRegister()) {
1875 if (!ArmAssembler::IsLowRegister(out.AsRegister<Register>())) {
1876 return false;
1877 }
1878 } else {
1879 DCHECK(out.IsRegisterPair());
1880
1881 if (!ArmAssembler::IsLowRegister(out.AsRegisterPairHigh<Register>())) {
1882 return false;
1883 }
1884 }
1885 }
1886
1887 return true;
1888}
1889
Anton Kirilov74234da2017-01-13 14:42:47 +00001890#undef __
1891// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1892#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
1893
Donghui Bai426b49c2016-11-08 14:55:38 +08001894Label* CodeGeneratorARM::GetFinalLabel(HInstruction* instruction, Label* final_label) {
1895 DCHECK(!instruction->IsControlFlow() && !instruction->IsSuspendCheck());
Anton Kirilov6f644202017-02-27 18:29:45 +00001896 DCHECK(!instruction->IsInvoke() || !instruction->GetLocations()->CanCall());
Donghui Bai426b49c2016-11-08 14:55:38 +08001897
1898 const HBasicBlock* const block = instruction->GetBlock();
1899 const HLoopInformation* const info = block->GetLoopInformation();
1900 HInstruction* const next = instruction->GetNext();
1901
1902 // Avoid a branch to a branch.
1903 if (next->IsGoto() && (info == nullptr ||
1904 !info->IsBackEdge(*block) ||
1905 !info->HasSuspendCheck())) {
1906 final_label = GetLabelOf(next->AsGoto()->GetSuccessor());
1907 }
1908
1909 return final_label;
1910}
1911
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001912void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001913 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001914}
1915
1916void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01001917 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01001918}
1919
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001920size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1921 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
1922 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001923}
1924
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001925size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1926 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
1927 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01001928}
1929
Nicolas Geoffray840e5462015-01-07 16:01:24 +00001930size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1931 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1932 return kArmWordSize;
1933}
1934
1935size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1936 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
1937 return kArmWordSize;
1938}
1939
Calin Juravle34166012014-12-19 17:22:29 +00001940CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +00001941 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +01001942 const CompilerOptions& compiler_options,
1943 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00001944 : CodeGenerator(graph,
1945 kNumberOfCoreRegisters,
1946 kNumberOfSRegisters,
1947 kNumberOfRegisterPairs,
1948 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1949 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +00001950 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1951 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01001952 compiler_options,
1953 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01001954 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001955 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001956 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +01001957 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +01001958 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +00001959 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001960 uint32_literals_(std::less<uint32_t>(),
1961 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00001962 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1963 boot_image_string_patches_(StringReferenceValueComparator(),
1964 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1965 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01001966 boot_image_type_patches_(TypeReferenceValueComparator(),
1967 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1968 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +00001969 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray132d8362016-11-16 09:19:42 +00001970 jit_string_patches_(StringReferenceValueComparator(),
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00001971 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
1972 jit_class_patches_(TypeReferenceValueComparator(),
1973 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -07001974 // Always save the LR register to mimic Quick.
1975 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +01001976}
1977
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001978void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
1979 // Ensure that we fix up branches and literal loads and emit the literal pool.
1980 __ FinalizeCode();
1981
1982 // Adjust native pc offsets in stack maps.
1983 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001984 uint32_t old_position =
1985 stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kThumb2);
Vladimir Markocf93a5c2015-06-16 11:33:24 +00001986 uint32_t new_position = __ GetAdjustedPosition(old_position);
1987 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
1988 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +01001989 // Adjust pc offsets for the disassembly information.
1990 if (disasm_info_ != nullptr) {
1991 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
1992 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
1993 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
1994 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
1995 it.second.start = __ GetAdjustedPosition(it.second.start);
1996 it.second.end = __ GetAdjustedPosition(it.second.end);
1997 }
1998 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
1999 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
2000 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
2001 }
2002 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002003
2004 CodeGenerator::Finalize(allocator);
2005}
2006
David Brazdil58282f42016-01-14 12:45:10 +00002007void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002008 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002009 blocked_core_registers_[SP] = true;
2010 blocked_core_registers_[LR] = true;
2011 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002012
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002013 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002014 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002015
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002016 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002017 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002018
David Brazdil58282f42016-01-14 12:45:10 +00002019 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +01002020 // Stubs do not save callee-save floating point registers. If the graph
2021 // is debuggable, we need to deal with these registers differently. For
2022 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002023 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
2024 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
2025 }
2026 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002027}
2028
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002029InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08002030 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002031 assembler_(codegen->GetAssembler()),
2032 codegen_(codegen) {}
2033
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002034void CodeGeneratorARM::ComputeSpillMask() {
2035 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
2036 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +00002037 // There is no easy instruction to restore just the PC on thumb2. We spill and
2038 // restore another arbitrary register.
2039 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002040 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
2041 // We use vpush and vpop for saving and restoring floating point registers, which take
2042 // a SRegister and the number of registers to save/restore after that SRegister. We
2043 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
2044 // but in the range.
2045 if (fpu_spill_mask_ != 0) {
2046 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
2047 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
2048 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
2049 fpu_spill_mask_ |= (1 << i);
2050 }
2051 }
2052}
2053
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002054static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002055 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002056}
2057
2058static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002059 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002060}
2061
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002062void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +00002063 bool skip_overflow_check =
2064 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002065 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00002066 __ Bind(&frame_entry_label_);
2067
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002068 if (HasEmptyFrame()) {
2069 return;
2070 }
2071
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002072 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002073 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
2074 __ LoadFromOffset(kLoadWord, IP, IP, 0);
2075 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002076 }
2077
Andreas Gampe501fd632015-09-10 16:11:06 -07002078 __ PushList(core_spill_mask_);
2079 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
2080 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002081 if (fpu_spill_mask_ != 0) {
2082 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2083 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002084 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +01002085 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002086 }
Mingyao Yang063fc772016-08-02 11:02:54 -07002087
2088 if (GetGraph()->HasShouldDeoptimizeFlag()) {
2089 // Initialize should_deoptimize flag to 0.
2090 __ mov(IP, ShifterOperand(0));
2091 __ StoreToOffset(kStoreWord, IP, SP, -kShouldDeoptimizeFlagSize);
2092 }
2093
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002094 int adjust = GetFrameSize() - FrameEntrySpillSize();
2095 __ AddConstant(SP, -adjust);
2096 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01002097
2098 // Save the current method if we need it. Note that we do not
2099 // do this in HCurrentMethod, as the instruction might have been removed
2100 // in the SSA graph.
2101 if (RequiresCurrentMethod()) {
2102 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
2103 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002104}
2105
2106void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002107 if (HasEmptyFrame()) {
2108 __ bx(LR);
2109 return;
2110 }
David Srbeckyc34dc932015-04-12 09:27:43 +01002111 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002112 int adjust = GetFrameSize() - FrameEntrySpillSize();
2113 __ AddConstant(SP, adjust);
2114 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002115 if (fpu_spill_mask_ != 0) {
2116 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2117 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
Andreas Gampe542451c2016-07-26 09:02:02 -07002118 __ cfi().AdjustCFAOffset(-static_cast<int>(kArmPointerSize) * POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002119 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002120 }
Andreas Gampe501fd632015-09-10 16:11:06 -07002121 // Pop LR into PC to return.
2122 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
2123 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
2124 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +01002125 __ cfi().RestoreState();
2126 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002127}
2128
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002129void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07002130 Label* label = GetLabelOf(block);
2131 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002132}
2133
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002134Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002135 switch (type) {
2136 case Primitive::kPrimBoolean:
2137 case Primitive::kPrimByte:
2138 case Primitive::kPrimChar:
2139 case Primitive::kPrimShort:
2140 case Primitive::kPrimInt:
2141 case Primitive::kPrimNot: {
2142 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002143 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002144 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002145 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002146 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002147 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002148 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002149 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002150
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002151 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002152 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002153 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002154 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002155 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002156 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002157 if (calling_convention.GetRegisterAt(index) == R1) {
2158 // Skip R1, and use R2_R3 instead.
2159 gp_index_++;
2160 index++;
2161 }
2162 }
2163 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
2164 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002165 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01002166
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002167 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002168 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002169 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002170 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
2171 }
2172 }
2173
2174 case Primitive::kPrimFloat: {
2175 uint32_t stack_index = stack_index_++;
2176 if (float_index_ % 2 == 0) {
2177 float_index_ = std::max(double_index_, float_index_);
2178 }
2179 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
2180 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
2181 } else {
2182 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
2183 }
2184 }
2185
2186 case Primitive::kPrimDouble: {
2187 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
2188 uint32_t stack_index = stack_index_;
2189 stack_index_ += 2;
2190 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
2191 uint32_t index = double_index_;
2192 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002193 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002194 calling_convention.GetFpuRegisterAt(index),
2195 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002196 DCHECK(ExpectedPairLayout(result));
2197 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002198 } else {
2199 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002200 }
2201 }
2202
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002203 case Primitive::kPrimVoid:
2204 LOG(FATAL) << "Unexpected parameter type " << type;
2205 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002206 }
Roland Levillain3b359c72015-11-17 19:35:12 +00002207 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002208}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002209
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002210Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002211 switch (type) {
2212 case Primitive::kPrimBoolean:
2213 case Primitive::kPrimByte:
2214 case Primitive::kPrimChar:
2215 case Primitive::kPrimShort:
2216 case Primitive::kPrimInt:
2217 case Primitive::kPrimNot: {
2218 return Location::RegisterLocation(R0);
2219 }
2220
2221 case Primitive::kPrimFloat: {
2222 return Location::FpuRegisterLocation(S0);
2223 }
2224
2225 case Primitive::kPrimLong: {
2226 return Location::RegisterPairLocation(R0, R1);
2227 }
2228
2229 case Primitive::kPrimDouble: {
2230 return Location::FpuRegisterPairLocation(S0, S1);
2231 }
2232
2233 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00002234 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002235 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002236
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002237 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002238}
2239
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002240Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
2241 return Location::RegisterLocation(kMethodRegisterArgument);
2242}
2243
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002244void CodeGeneratorARM::Move32(Location destination, Location source) {
2245 if (source.Equals(destination)) {
2246 return;
2247 }
2248 if (destination.IsRegister()) {
2249 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002250 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002251 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002252 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002253 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002254 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002255 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002256 } else if (destination.IsFpuRegister()) {
2257 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002258 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002259 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002260 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002261 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002262 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002263 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002264 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002265 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002266 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002267 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002268 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002269 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002270 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002271 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002272 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
2273 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002274 }
2275 }
2276}
2277
2278void CodeGeneratorARM::Move64(Location destination, Location source) {
2279 if (source.Equals(destination)) {
2280 return;
2281 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002282 if (destination.IsRegisterPair()) {
2283 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002284 EmitParallelMoves(
2285 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
2286 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002287 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002288 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002289 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
2290 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002291 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002292 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002293 } else if (source.IsFpuRegisterPair()) {
2294 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
2295 destination.AsRegisterPairHigh<Register>(),
2296 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002297 } else {
2298 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002299 DCHECK(ExpectedPairLayout(destination));
2300 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
2301 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002302 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002303 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002304 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002305 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2306 SP,
2307 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01002308 } else if (source.IsRegisterPair()) {
2309 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2310 source.AsRegisterPairLow<Register>(),
2311 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002312 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002313 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002314 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002315 } else {
2316 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002317 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002318 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002319 if (source.AsRegisterPairLow<Register>() == R1) {
2320 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002321 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
2322 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002323 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002324 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002325 SP, destination.GetStackIndex());
2326 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002327 } else if (source.IsFpuRegisterPair()) {
2328 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
2329 SP,
2330 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002331 } else {
2332 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002333 EmitParallelMoves(
2334 Location::StackSlot(source.GetStackIndex()),
2335 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002336 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002337 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002338 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
2339 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002340 }
2341 }
2342}
2343
Calin Juravle175dc732015-08-25 15:42:32 +01002344void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
2345 DCHECK(location.IsRegister());
2346 __ LoadImmediate(location.AsRegister<Register>(), value);
2347}
2348
Calin Juravlee460d1d2015-09-29 04:52:17 +01002349void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00002350 HParallelMove move(GetGraph()->GetArena());
2351 move.AddMove(src, dst, dst_type, nullptr);
2352 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002353}
2354
2355void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
2356 if (location.IsRegister()) {
2357 locations->AddTemp(location);
2358 } else if (location.IsRegisterPair()) {
2359 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
2360 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
2361 } else {
2362 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
2363 }
2364}
2365
Calin Juravle175dc732015-08-25 15:42:32 +01002366void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
2367 HInstruction* instruction,
2368 uint32_t dex_pc,
2369 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01002370 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002371 GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
Serban Constantinescuda8ffec2016-03-09 12:02:11 +00002372 if (EntrypointRequiresStackMap(entrypoint)) {
2373 RecordPcInfo(instruction, dex_pc, slow_path);
2374 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002375}
2376
Roland Levillaindec8f632016-07-22 17:10:06 +01002377void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
2378 HInstruction* instruction,
2379 SlowPathCode* slow_path) {
2380 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002381 GenerateInvokeRuntime(entry_point_offset);
2382}
2383
2384void CodeGeneratorARM::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01002385 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
2386 __ blx(LR);
2387}
2388
David Brazdilfc6a86a2015-06-26 10:33:45 +00002389void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002390 DCHECK(!successor->IsExitBlock());
2391
2392 HBasicBlock* block = got->GetBlock();
2393 HInstruction* previous = got->GetPrevious();
2394
2395 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00002396 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002397 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2398 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2399 return;
2400 }
2401
2402 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2403 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2404 }
2405 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002406 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002407 }
2408}
2409
David Brazdilfc6a86a2015-06-26 10:33:45 +00002410void LocationsBuilderARM::VisitGoto(HGoto* got) {
2411 got->SetLocations(nullptr);
2412}
2413
2414void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
2415 HandleGoto(got, got->GetSuccessor());
2416}
2417
2418void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2419 try_boundary->SetLocations(nullptr);
2420}
2421
2422void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2423 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2424 if (!successor->IsExitBlock()) {
2425 HandleGoto(try_boundary, successor);
2426 }
2427}
2428
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002429void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002430 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002431}
2432
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002433void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002434}
2435
Roland Levillain4fa13f62015-07-06 18:11:54 +01002436void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
2437 Label* true_label,
2438 Label* false_label) {
2439 LocationSummary* locations = cond->GetLocations();
2440 Location left = locations->InAt(0);
2441 Location right = locations->InAt(1);
2442 IfCondition if_cond = cond->GetCondition();
2443
2444 Register left_high = left.AsRegisterPairHigh<Register>();
2445 Register left_low = left.AsRegisterPairLow<Register>();
2446 IfCondition true_high_cond = if_cond;
2447 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07002448 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
Roland Levillain4fa13f62015-07-06 18:11:54 +01002449
2450 // Set the conditions for the test, remembering that == needs to be
2451 // decided using the low words.
2452 switch (if_cond) {
2453 case kCondEQ:
2454 case kCondNE:
2455 // Nothing to do.
2456 break;
2457 case kCondLT:
2458 false_high_cond = kCondGT;
2459 break;
2460 case kCondLE:
2461 true_high_cond = kCondLT;
2462 break;
2463 case kCondGT:
2464 false_high_cond = kCondLT;
2465 break;
2466 case kCondGE:
2467 true_high_cond = kCondGT;
2468 break;
Aart Bike9f37602015-10-09 11:15:55 -07002469 case kCondB:
2470 false_high_cond = kCondA;
2471 break;
2472 case kCondBE:
2473 true_high_cond = kCondB;
2474 break;
2475 case kCondA:
2476 false_high_cond = kCondB;
2477 break;
2478 case kCondAE:
2479 true_high_cond = kCondA;
2480 break;
Roland Levillain4fa13f62015-07-06 18:11:54 +01002481 }
2482 if (right.IsConstant()) {
2483 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
2484 int32_t val_low = Low32Bits(value);
2485 int32_t val_high = High32Bits(value);
2486
Vladimir Markoac6ac102015-12-17 12:14:00 +00002487 __ CmpConstant(left_high, val_high);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002488 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07002489 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002490 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07002491 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002492 } else {
Aart Bike9f37602015-10-09 11:15:55 -07002493 __ b(true_label, ARMCondition(true_high_cond));
2494 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002495 }
2496 // Must be equal high, so compare the lows.
Vladimir Markoac6ac102015-12-17 12:14:00 +00002497 __ CmpConstant(left_low, val_low);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002498 } else {
2499 Register right_high = right.AsRegisterPairHigh<Register>();
2500 Register right_low = right.AsRegisterPairLow<Register>();
2501
2502 __ cmp(left_high, ShifterOperand(right_high));
2503 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07002504 __ b(true_label, ARMCondition(true_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002505 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07002506 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002507 } else {
Aart Bike9f37602015-10-09 11:15:55 -07002508 __ b(true_label, ARMCondition(true_high_cond));
2509 __ b(false_label, ARMCondition(false_high_cond));
Roland Levillain4fa13f62015-07-06 18:11:54 +01002510 }
2511 // Must be equal high, so compare the lows.
2512 __ cmp(left_low, ShifterOperand(right_low));
2513 }
2514 // The last comparison might be unsigned.
Aart Bike9f37602015-10-09 11:15:55 -07002515 // TODO: optimize cases where this is always true/false
Roland Levillain4fa13f62015-07-06 18:11:54 +01002516 __ b(true_label, final_condition);
2517}
2518
David Brazdil0debae72015-11-12 18:37:00 +00002519void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
2520 Label* true_target_in,
2521 Label* false_target_in) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002522 if (CanGenerateTest(condition, codegen_->GetAssembler())) {
2523 Label* non_fallthrough_target;
2524 bool invert;
2525
2526 if (true_target_in == nullptr) {
2527 DCHECK(false_target_in != nullptr);
2528 non_fallthrough_target = false_target_in;
2529 invert = true;
2530 } else {
2531 non_fallthrough_target = true_target_in;
2532 invert = false;
2533 }
2534
2535 const auto cond = GenerateTest(condition, invert, codegen_);
2536
2537 __ b(non_fallthrough_target, cond.first);
2538
2539 if (false_target_in != nullptr && false_target_in != non_fallthrough_target) {
2540 __ b(false_target_in);
2541 }
2542
2543 return;
2544 }
2545
David Brazdil0debae72015-11-12 18:37:00 +00002546 // Generated branching requires both targets to be explicit. If either of the
2547 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
2548 Label fallthrough_target;
2549 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
2550 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
2551
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002552 DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
2553 GenerateLongComparesAndJumps(condition, true_target, false_target);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002554
David Brazdil0debae72015-11-12 18:37:00 +00002555 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002556 __ b(false_target);
2557 }
David Brazdil0debae72015-11-12 18:37:00 +00002558
2559 if (fallthrough_target.IsLinked()) {
2560 __ Bind(&fallthrough_target);
2561 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01002562}
2563
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002564void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00002565 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002566 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00002567 Label* false_target) {
2568 HInstruction* cond = instruction->InputAt(condition_input_index);
2569
2570 if (true_target == nullptr && false_target == nullptr) {
2571 // Nothing to do. The code always falls through.
2572 return;
2573 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00002574 // Constant condition, statically compared against "true" (integer value 1).
2575 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00002576 if (true_target != nullptr) {
2577 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002578 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002579 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00002580 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00002581 if (false_target != nullptr) {
2582 __ b(false_target);
2583 }
2584 }
2585 return;
2586 }
2587
2588 // The following code generates these patterns:
2589 // (1) true_target == nullptr && false_target != nullptr
2590 // - opposite condition true => branch to false_target
2591 // (2) true_target != nullptr && false_target == nullptr
2592 // - condition true => branch to true_target
2593 // (3) true_target != nullptr && false_target != nullptr
2594 // - condition true => branch to true_target
2595 // - branch to false_target
2596 if (IsBooleanValueOrMaterializedCondition(cond)) {
2597 // Condition has been materialized, compare the output to 0.
2598 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
2599 DCHECK(cond_val.IsRegister());
2600 if (true_target == nullptr) {
2601 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
2602 } else {
2603 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002604 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002605 } else {
David Brazdil0debae72015-11-12 18:37:00 +00002606 // Condition has not been materialized. Use its inputs as the comparison and
2607 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04002608 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00002609
2610 // If this is a long or FP comparison that has been folded into
2611 // the HCondition, generate the comparison directly.
2612 Primitive::Type type = condition->InputAt(0)->GetType();
2613 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
2614 GenerateCompareTestAndBranch(condition, true_target, false_target);
2615 return;
2616 }
2617
Donghui Bai426b49c2016-11-08 14:55:38 +08002618 Label* non_fallthrough_target;
2619 Condition arm_cond;
David Brazdil0debae72015-11-12 18:37:00 +00002620 LocationSummary* locations = cond->GetLocations();
2621 DCHECK(locations->InAt(0).IsRegister());
2622 Register left = locations->InAt(0).AsRegister<Register>();
2623 Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08002624
David Brazdil0debae72015-11-12 18:37:00 +00002625 if (true_target == nullptr) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002626 arm_cond = ARMCondition(condition->GetOppositeCondition());
2627 non_fallthrough_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00002628 } else {
Donghui Bai426b49c2016-11-08 14:55:38 +08002629 arm_cond = ARMCondition(condition->GetCondition());
2630 non_fallthrough_target = true_target;
2631 }
2632
2633 if (right.IsConstant() && (arm_cond == NE || arm_cond == EQ) &&
2634 CodeGenerator::GetInt32ValueOf(right.GetConstant()) == 0) {
2635 if (arm_cond == EQ) {
2636 __ CompareAndBranchIfZero(left, non_fallthrough_target);
2637 } else {
2638 DCHECK_EQ(arm_cond, NE);
2639 __ CompareAndBranchIfNonZero(left, non_fallthrough_target);
2640 }
2641 } else {
2642 if (right.IsRegister()) {
2643 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
2644 } else {
2645 DCHECK(right.IsConstant());
2646 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
2647 }
2648
2649 __ b(non_fallthrough_target, arm_cond);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002650 }
Dave Allison20dfc792014-06-16 20:44:29 -07002651 }
David Brazdil0debae72015-11-12 18:37:00 +00002652
2653 // If neither branch falls through (case 3), the conditional branch to `true_target`
2654 // was already emitted (case 2) and we need to emit a jump to `false_target`.
2655 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002656 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002657 }
2658}
2659
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002660void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00002661 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
2662 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002663 locations->SetInAt(0, Location::RequiresRegister());
2664 }
2665}
2666
2667void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00002668 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
2669 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
2670 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
2671 nullptr : codegen_->GetLabelOf(true_successor);
2672 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
2673 nullptr : codegen_->GetLabelOf(false_successor);
2674 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002675}
2676
2677void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
2678 LocationSummary* locations = new (GetGraph()->GetArena())
2679 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01002680 InvokeRuntimeCallingConvention calling_convention;
2681 RegisterSet caller_saves = RegisterSet::Empty();
2682 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2683 locations->SetCustomSlowPathCallerSaves(caller_saves);
David Brazdil0debae72015-11-12 18:37:00 +00002684 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002685 locations->SetInAt(0, Location::RequiresRegister());
2686 }
2687}
2688
2689void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01002690 SlowPathCodeARM* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00002691 GenerateTestAndBranch(deoptimize,
2692 /* condition_input_index */ 0,
2693 slow_path->GetEntryLabel(),
2694 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002695}
Dave Allison20dfc792014-06-16 20:44:29 -07002696
Mingyao Yang063fc772016-08-02 11:02:54 -07002697void LocationsBuilderARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2698 LocationSummary* locations = new (GetGraph()->GetArena())
2699 LocationSummary(flag, LocationSummary::kNoCall);
2700 locations->SetOut(Location::RequiresRegister());
2701}
2702
2703void InstructionCodeGeneratorARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2704 __ LoadFromOffset(kLoadWord,
2705 flag->GetLocations()->Out().AsRegister<Register>(),
2706 SP,
2707 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
2708}
2709
David Brazdil74eb1b22015-12-14 11:44:01 +00002710void LocationsBuilderARM::VisitSelect(HSelect* select) {
2711 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
Donghui Bai426b49c2016-11-08 14:55:38 +08002712 const bool is_floating_point = Primitive::IsFloatingPointType(select->GetType());
2713
2714 if (is_floating_point) {
David Brazdil74eb1b22015-12-14 11:44:01 +00002715 locations->SetInAt(0, Location::RequiresFpuRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08002716 locations->SetInAt(1, Location::FpuRegisterOrConstant(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00002717 } else {
2718 locations->SetInAt(0, Location::RequiresRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08002719 locations->SetInAt(1, Arm8BitEncodableConstantOrRegister(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00002720 }
Donghui Bai426b49c2016-11-08 14:55:38 +08002721
David Brazdil74eb1b22015-12-14 11:44:01 +00002722 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002723 locations->SetInAt(2, Location::RegisterOrConstant(select->GetCondition()));
2724 // The code generator handles overlap with the values, but not with the condition.
2725 locations->SetOut(Location::SameAsFirstInput());
2726 } else if (is_floating_point) {
2727 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2728 } else {
2729 if (!locations->InAt(1).IsConstant()) {
2730 locations->SetInAt(0, Arm8BitEncodableConstantOrRegister(select->GetFalseValue()));
2731 }
2732
2733 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
David Brazdil74eb1b22015-12-14 11:44:01 +00002734 }
David Brazdil74eb1b22015-12-14 11:44:01 +00002735}
2736
2737void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002738 HInstruction* const condition = select->GetCondition();
2739 const LocationSummary* const locations = select->GetLocations();
2740 const Primitive::Type type = select->GetType();
2741 const Location first = locations->InAt(0);
2742 const Location out = locations->Out();
2743 const Location second = locations->InAt(1);
2744 Location src;
2745
2746 if (condition->IsIntConstant()) {
2747 if (condition->AsIntConstant()->IsFalse()) {
2748 src = first;
2749 } else {
2750 src = second;
2751 }
2752
2753 codegen_->MoveLocation(out, src, type);
2754 return;
2755 }
2756
2757 if (!Primitive::IsFloatingPointType(type) &&
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002758 (IsBooleanValueOrMaterializedCondition(condition) ||
2759 CanGenerateTest(condition->AsCondition(), codegen_->GetAssembler()))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002760 bool invert = false;
2761
2762 if (out.Equals(second)) {
2763 src = first;
2764 invert = true;
2765 } else if (out.Equals(first)) {
2766 src = second;
2767 } else if (second.IsConstant()) {
2768 DCHECK(CanEncodeConstantAs8BitImmediate(second.GetConstant()));
2769 src = second;
2770 } else if (first.IsConstant()) {
2771 DCHECK(CanEncodeConstantAs8BitImmediate(first.GetConstant()));
2772 src = first;
2773 invert = true;
2774 } else {
2775 src = second;
2776 }
2777
2778 if (CanGenerateConditionalMove(out, src)) {
2779 if (!out.Equals(first) && !out.Equals(second)) {
2780 codegen_->MoveLocation(out, src.Equals(first) ? second : first, type);
2781 }
2782
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002783 std::pair<Condition, Condition> cond;
2784
2785 if (IsBooleanValueOrMaterializedCondition(condition)) {
2786 __ CmpConstant(locations->InAt(2).AsRegister<Register>(), 0);
2787 cond = invert ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
2788 } else {
2789 cond = GenerateTest(condition->AsCondition(), invert, codegen_);
2790 }
Donghui Bai426b49c2016-11-08 14:55:38 +08002791
2792 if (out.IsRegister()) {
2793 ShifterOperand operand;
2794
2795 if (src.IsConstant()) {
2796 operand = ShifterOperand(CodeGenerator::GetInt32ValueOf(src.GetConstant()));
2797 } else {
2798 DCHECK(src.IsRegister());
2799 operand = ShifterOperand(src.AsRegister<Register>());
2800 }
2801
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002802 __ it(cond.first);
2803 __ mov(out.AsRegister<Register>(), operand, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08002804 } else {
2805 DCHECK(out.IsRegisterPair());
2806
2807 ShifterOperand operand_high;
2808 ShifterOperand operand_low;
2809
2810 if (src.IsConstant()) {
2811 const int64_t value = src.GetConstant()->AsLongConstant()->GetValue();
2812
2813 operand_high = ShifterOperand(High32Bits(value));
2814 operand_low = ShifterOperand(Low32Bits(value));
2815 } else {
2816 DCHECK(src.IsRegisterPair());
2817 operand_high = ShifterOperand(src.AsRegisterPairHigh<Register>());
2818 operand_low = ShifterOperand(src.AsRegisterPairLow<Register>());
2819 }
2820
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002821 __ it(cond.first);
2822 __ mov(out.AsRegisterPairLow<Register>(), operand_low, cond.first);
2823 __ it(cond.first);
2824 __ mov(out.AsRegisterPairHigh<Register>(), operand_high, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08002825 }
2826
2827 return;
2828 }
2829 }
2830
2831 Label* false_target = nullptr;
2832 Label* true_target = nullptr;
2833 Label select_end;
2834 Label* target = codegen_->GetFinalLabel(select, &select_end);
2835
2836 if (out.Equals(second)) {
2837 true_target = target;
2838 src = first;
2839 } else {
2840 false_target = target;
2841 src = second;
2842
2843 if (!out.Equals(first)) {
2844 codegen_->MoveLocation(out, first, type);
2845 }
2846 }
2847
2848 GenerateTestAndBranch(select, 2, true_target, false_target);
2849 codegen_->MoveLocation(out, src, type);
2850
2851 if (select_end.IsLinked()) {
2852 __ Bind(&select_end);
2853 }
David Brazdil74eb1b22015-12-14 11:44:01 +00002854}
2855
David Srbecky0cf44932015-12-09 14:09:59 +00002856void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
2857 new (GetGraph()->GetArena()) LocationSummary(info);
2858}
2859
David Srbeckyd28f4a02016-03-14 17:14:24 +00002860void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
2861 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00002862}
2863
2864void CodeGeneratorARM::GenerateNop() {
2865 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00002866}
2867
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002868void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002869 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01002870 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002871 // Handle the long/FP comparisons made in instruction simplification.
2872 switch (cond->InputAt(0)->GetType()) {
2873 case Primitive::kPrimLong:
2874 locations->SetInAt(0, Location::RequiresRegister());
2875 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002876 if (!cond->IsEmittedAtUseSite()) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002877 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002878 }
2879 break;
2880
2881 case Primitive::kPrimFloat:
2882 case Primitive::kPrimDouble:
2883 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01002884 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002885 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002886 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2887 }
2888 break;
2889
2890 default:
2891 locations->SetInAt(0, Location::RequiresRegister());
2892 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00002893 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002894 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2895 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002896 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002897}
2898
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002899void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002900 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002901 return;
Dave Allison20dfc792014-06-16 20:44:29 -07002902 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01002903
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002904 const Register out = cond->GetLocations()->Out().AsRegister<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01002905
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002906 if (ArmAssembler::IsLowRegister(out) && CanGenerateTest(cond, codegen_->GetAssembler())) {
2907 const auto condition = GenerateTest(cond, false, codegen_);
2908
2909 __ it(condition.first);
2910 __ mov(out, ShifterOperand(1), condition.first);
2911 __ it(condition.second);
2912 __ mov(out, ShifterOperand(0), condition.second);
2913 return;
Roland Levillain4fa13f62015-07-06 18:11:54 +01002914 }
2915
2916 // Convert the jumps into the result.
2917 Label done_label;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002918 Label* const final_label = codegen_->GetFinalLabel(cond, &done_label);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002919
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002920 if (cond->InputAt(0)->GetType() == Primitive::kPrimLong) {
2921 Label true_label, false_label;
Roland Levillain4fa13f62015-07-06 18:11:54 +01002922
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002923 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
2924
2925 // False case: result = 0.
2926 __ Bind(&false_label);
2927 __ LoadImmediate(out, 0);
2928 __ b(final_label);
2929
2930 // True case: result = 1.
2931 __ Bind(&true_label);
2932 __ LoadImmediate(out, 1);
2933 } else {
2934 DCHECK(CanGenerateTest(cond, codegen_->GetAssembler()));
2935
2936 const auto condition = GenerateTest(cond, false, codegen_);
2937
2938 __ mov(out, ShifterOperand(0), AL, kCcKeep);
2939 __ b(final_label, condition.second);
2940 __ LoadImmediate(out, 1);
2941 }
Anton Kirilov6f644202017-02-27 18:29:45 +00002942
2943 if (done_label.IsLinked()) {
2944 __ Bind(&done_label);
2945 }
Dave Allison20dfc792014-06-16 20:44:29 -07002946}
2947
2948void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002949 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002950}
2951
2952void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002953 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002954}
2955
2956void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002957 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002958}
2959
2960void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002961 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002962}
2963
2964void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002965 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002966}
2967
2968void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002969 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002970}
2971
2972void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002973 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002974}
2975
2976void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002977 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002978}
2979
2980void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002981 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002982}
2983
2984void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002985 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002986}
2987
2988void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002989 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07002990}
2991
2992void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002993 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002994}
2995
Aart Bike9f37602015-10-09 11:15:55 -07002996void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002997 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07002998}
2999
3000void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003001 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003002}
3003
3004void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003005 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003006}
3007
3008void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003009 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003010}
3011
3012void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003013 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003014}
3015
3016void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003017 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003018}
3019
3020void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003021 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003022}
3023
3024void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003025 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003026}
3027
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003028void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003029 LocationSummary* locations =
3030 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003031 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003032}
3033
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003034void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01003035 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003036}
3037
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003038void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
3039 LocationSummary* locations =
3040 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3041 locations->SetOut(Location::ConstantLocation(constant));
3042}
3043
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003044void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003045 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003046}
3047
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003048void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003049 LocationSummary* locations =
3050 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003051 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003052}
3053
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003054void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003055 // Will be generated at use site.
3056}
3057
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003058void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
3059 LocationSummary* locations =
3060 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3061 locations->SetOut(Location::ConstantLocation(constant));
3062}
3063
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003064void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003065 // Will be generated at use site.
3066}
3067
3068void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
3069 LocationSummary* locations =
3070 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3071 locations->SetOut(Location::ConstantLocation(constant));
3072}
3073
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003074void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003075 // Will be generated at use site.
3076}
3077
Igor Murashkind01745e2017-04-05 16:40:31 -07003078void LocationsBuilderARM::VisitConstructorFence(HConstructorFence* constructor_fence) {
3079 constructor_fence->SetLocations(nullptr);
3080}
3081
3082void InstructionCodeGeneratorARM::VisitConstructorFence(
3083 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
3084 codegen_->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
3085}
3086
Calin Juravle27df7582015-04-17 19:12:31 +01003087void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
3088 memory_barrier->SetLocations(nullptr);
3089}
3090
3091void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00003092 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01003093}
3094
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003095void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003096 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003097}
3098
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003099void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003100 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003101}
3102
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003103void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003104 LocationSummary* locations =
3105 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003106 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003107}
3108
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003109void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003110 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003111}
3112
Calin Juravle175dc732015-08-25 15:42:32 +01003113void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3114 // The trampoline uses the same calling convention as dex calling conventions,
3115 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
3116 // the method_idx.
3117 HandleInvoke(invoke);
3118}
3119
3120void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3121 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
3122}
3123
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003124void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003125 // Explicit clinit checks triggered by static invokes must have been pruned by
3126 // art::PrepareForRegisterAllocation.
3127 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003128
Vladimir Marko68c981f2016-08-26 13:13:33 +01003129 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003130 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00003131 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
3132 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
3133 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003134 return;
3135 }
3136
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003137 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00003138
3139 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
3140 if (invoke->HasPcRelativeDexCache()) {
3141 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
3142 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003143}
3144
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003145static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
3146 if (invoke->GetLocations()->Intrinsified()) {
3147 IntrinsicCodeGeneratorARM intrinsic(codegen);
3148 intrinsic.Dispatch(invoke);
3149 return true;
3150 }
3151 return false;
3152}
3153
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003154void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003155 // Explicit clinit checks triggered by static invokes must have been pruned by
3156 // art::PrepareForRegisterAllocation.
3157 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003158
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003159 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3160 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00003161 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003162
Nicolas Geoffray38207af2015-06-01 15:46:22 +01003163 LocationSummary* locations = invoke->GetLocations();
3164 codegen_->GenerateStaticOrDirectCall(
3165 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00003166 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003167}
3168
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003169void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01003170 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01003171 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003172}
3173
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003174void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Vladimir Marko68c981f2016-08-26 13:13:33 +01003175 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003176 if (intrinsic.TryDispatch(invoke)) {
3177 return;
3178 }
3179
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003180 HandleInvoke(invoke);
3181}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003182
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003183void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003184 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3185 return;
3186 }
3187
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003188 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003189 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003190 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003191}
3192
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003193void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3194 HandleInvoke(invoke);
3195 // Add the hidden argument.
3196 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
3197}
3198
3199void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3200 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00003201 LocationSummary* locations = invoke->GetLocations();
3202 Register temp = locations->GetTemp(0).AsRegister<Register>();
3203 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003204 Location receiver = locations->InAt(0);
3205 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3206
Roland Levillain3b359c72015-11-17 19:35:12 +00003207 // Set the hidden argument. This is safe to do this here, as R12
3208 // won't be modified thereafter, before the `blx` (call) instruction.
3209 DCHECK_EQ(R12, hidden_reg);
3210 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003211
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003212 if (receiver.IsStackSlot()) {
3213 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00003214 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003215 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
3216 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00003217 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00003218 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003219 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003220 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00003221 // Instead of simply (possibly) unpoisoning `temp` here, we should
3222 // emit a read barrier for the previous class reference load.
3223 // However this is not required in practice, as this is an
3224 // intermediate/temporary reference and because the current
3225 // concurrent copying collector keeps the from-space memory
3226 // intact/accessible until the end of the marking phase (the
3227 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01003228 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003229 __ LoadFromOffset(kLoadWord, temp, temp,
3230 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
3231 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00003232 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003233 // temp = temp->GetImtEntryAt(method_offset);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003234 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00003235 uint32_t entry_point =
Andreas Gampe542451c2016-07-26 09:02:02 -07003236 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003237 // LR = temp->GetEntryPoint();
3238 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
3239 // LR();
3240 __ blx(LR);
3241 DCHECK(!codegen_->IsLeafMethod());
3242 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3243}
3244
Orion Hodsonac141392017-01-13 11:53:47 +00003245void LocationsBuilderARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3246 HandleInvoke(invoke);
3247}
3248
3249void InstructionCodeGeneratorARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3250 codegen_->GenerateInvokePolymorphicCall(invoke);
3251}
3252
Roland Levillain88cb1752014-10-20 16:36:47 +01003253void LocationsBuilderARM::VisitNeg(HNeg* neg) {
3254 LocationSummary* locations =
3255 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
3256 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003257 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01003258 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003259 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3260 break;
3261 }
3262 case Primitive::kPrimLong: {
3263 locations->SetInAt(0, Location::RequiresRegister());
3264 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003265 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003266 }
Roland Levillain88cb1752014-10-20 16:36:47 +01003267
Roland Levillain88cb1752014-10-20 16:36:47 +01003268 case Primitive::kPrimFloat:
3269 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003270 locations->SetInAt(0, Location::RequiresFpuRegister());
3271 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003272 break;
3273
3274 default:
3275 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3276 }
3277}
3278
3279void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
3280 LocationSummary* locations = neg->GetLocations();
3281 Location out = locations->Out();
3282 Location in = locations->InAt(0);
3283 switch (neg->GetResultType()) {
3284 case Primitive::kPrimInt:
3285 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003286 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01003287 break;
3288
3289 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003290 DCHECK(in.IsRegisterPair());
3291 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
3292 __ rsbs(out.AsRegisterPairLow<Register>(),
3293 in.AsRegisterPairLow<Register>(),
3294 ShifterOperand(0));
3295 // We cannot emit an RSC (Reverse Subtract with Carry)
3296 // instruction here, as it does not exist in the Thumb-2
3297 // instruction set. We use the following approach
3298 // using SBC and SUB instead.
3299 //
3300 // out.hi = -C
3301 __ sbc(out.AsRegisterPairHigh<Register>(),
3302 out.AsRegisterPairHigh<Register>(),
3303 ShifterOperand(out.AsRegisterPairHigh<Register>()));
3304 // out.hi = out.hi - in.hi
3305 __ sub(out.AsRegisterPairHigh<Register>(),
3306 out.AsRegisterPairHigh<Register>(),
3307 ShifterOperand(in.AsRegisterPairHigh<Register>()));
3308 break;
3309
Roland Levillain88cb1752014-10-20 16:36:47 +01003310 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003311 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003312 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00003313 break;
3314
Roland Levillain88cb1752014-10-20 16:36:47 +01003315 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003316 DCHECK(in.IsFpuRegisterPair());
3317 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3318 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01003319 break;
3320
3321 default:
3322 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3323 }
3324}
3325
Roland Levillaindff1f282014-11-05 14:15:05 +00003326void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00003327 Primitive::Type result_type = conversion->GetResultType();
3328 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003329 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00003330
Roland Levillain5b3ee562015-04-14 16:02:41 +01003331 // The float-to-long, double-to-long and long-to-float type conversions
3332 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00003333 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01003334 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
3335 && result_type == Primitive::kPrimLong)
3336 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003337 ? LocationSummary::kCallOnMainOnly
Roland Levillain624279f2014-12-04 11:54:28 +00003338 : LocationSummary::kNoCall;
3339 LocationSummary* locations =
3340 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
3341
David Brazdilb2bd1c52015-03-25 11:17:37 +00003342 // The Java language does not allow treating boolean as an integral type but
3343 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00003344
Roland Levillaindff1f282014-11-05 14:15:05 +00003345 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003346 case Primitive::kPrimByte:
3347 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003348 case Primitive::kPrimLong:
3349 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003350 case Primitive::kPrimBoolean:
3351 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003352 case Primitive::kPrimShort:
3353 case Primitive::kPrimInt:
3354 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003355 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003356 locations->SetInAt(0, Location::RequiresRegister());
3357 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3358 break;
3359
3360 default:
3361 LOG(FATAL) << "Unexpected type conversion from " << input_type
3362 << " to " << result_type;
3363 }
3364 break;
3365
Roland Levillain01a8d712014-11-14 16:27:39 +00003366 case Primitive::kPrimShort:
3367 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003368 case Primitive::kPrimLong:
3369 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003370 case Primitive::kPrimBoolean:
3371 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00003372 case Primitive::kPrimByte:
3373 case Primitive::kPrimInt:
3374 case Primitive::kPrimChar:
3375 // Processing a Dex `int-to-short' instruction.
3376 locations->SetInAt(0, Location::RequiresRegister());
3377 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3378 break;
3379
3380 default:
3381 LOG(FATAL) << "Unexpected type conversion from " << input_type
3382 << " to " << result_type;
3383 }
3384 break;
3385
Roland Levillain946e1432014-11-11 17:35:19 +00003386 case Primitive::kPrimInt:
3387 switch (input_type) {
3388 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00003389 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00003390 locations->SetInAt(0, Location::Any());
3391 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3392 break;
3393
3394 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00003395 // Processing a Dex `float-to-int' instruction.
3396 locations->SetInAt(0, Location::RequiresFpuRegister());
3397 locations->SetOut(Location::RequiresRegister());
3398 locations->AddTemp(Location::RequiresFpuRegister());
3399 break;
3400
Roland Levillain946e1432014-11-11 17:35:19 +00003401 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003402 // Processing a Dex `double-to-int' instruction.
3403 locations->SetInAt(0, Location::RequiresFpuRegister());
3404 locations->SetOut(Location::RequiresRegister());
3405 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00003406 break;
3407
3408 default:
3409 LOG(FATAL) << "Unexpected type conversion from " << input_type
3410 << " to " << result_type;
3411 }
3412 break;
3413
Roland Levillaindff1f282014-11-05 14:15:05 +00003414 case Primitive::kPrimLong:
3415 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003416 case Primitive::kPrimBoolean:
3417 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00003418 case Primitive::kPrimByte:
3419 case Primitive::kPrimShort:
3420 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00003421 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003422 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00003423 locations->SetInAt(0, Location::RequiresRegister());
3424 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3425 break;
3426
Roland Levillain624279f2014-12-04 11:54:28 +00003427 case Primitive::kPrimFloat: {
3428 // Processing a Dex `float-to-long' instruction.
3429 InvokeRuntimeCallingConvention calling_convention;
3430 locations->SetInAt(0, Location::FpuRegisterLocation(
3431 calling_convention.GetFpuRegisterAt(0)));
3432 locations->SetOut(Location::RegisterPairLocation(R0, R1));
3433 break;
3434 }
3435
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003436 case Primitive::kPrimDouble: {
3437 // Processing a Dex `double-to-long' instruction.
3438 InvokeRuntimeCallingConvention calling_convention;
3439 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3440 calling_convention.GetFpuRegisterAt(0),
3441 calling_convention.GetFpuRegisterAt(1)));
3442 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00003443 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003444 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003445
3446 default:
3447 LOG(FATAL) << "Unexpected type conversion from " << input_type
3448 << " to " << result_type;
3449 }
3450 break;
3451
Roland Levillain981e4542014-11-14 11:47:14 +00003452 case Primitive::kPrimChar:
3453 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003454 case Primitive::kPrimLong:
3455 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003456 case Primitive::kPrimBoolean:
3457 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00003458 case Primitive::kPrimByte:
3459 case Primitive::kPrimShort:
3460 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00003461 // Processing a Dex `int-to-char' instruction.
3462 locations->SetInAt(0, Location::RequiresRegister());
3463 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3464 break;
3465
3466 default:
3467 LOG(FATAL) << "Unexpected type conversion from " << input_type
3468 << " to " << result_type;
3469 }
3470 break;
3471
Roland Levillaindff1f282014-11-05 14:15:05 +00003472 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00003473 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003474 case Primitive::kPrimBoolean:
3475 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003476 case Primitive::kPrimByte:
3477 case Primitive::kPrimShort:
3478 case Primitive::kPrimInt:
3479 case Primitive::kPrimChar:
3480 // Processing a Dex `int-to-float' instruction.
3481 locations->SetInAt(0, Location::RequiresRegister());
3482 locations->SetOut(Location::RequiresFpuRegister());
3483 break;
3484
Roland Levillain5b3ee562015-04-14 16:02:41 +01003485 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00003486 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01003487 InvokeRuntimeCallingConvention calling_convention;
3488 locations->SetInAt(0, Location::RegisterPairLocation(
3489 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3490 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00003491 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01003492 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00003493
Roland Levillaincff13742014-11-17 14:32:17 +00003494 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003495 // Processing a Dex `double-to-float' instruction.
3496 locations->SetInAt(0, Location::RequiresFpuRegister());
3497 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003498 break;
3499
3500 default:
3501 LOG(FATAL) << "Unexpected type conversion from " << input_type
3502 << " to " << result_type;
3503 };
3504 break;
3505
Roland Levillaindff1f282014-11-05 14:15:05 +00003506 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00003507 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003508 case Primitive::kPrimBoolean:
3509 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003510 case Primitive::kPrimByte:
3511 case Primitive::kPrimShort:
3512 case Primitive::kPrimInt:
3513 case Primitive::kPrimChar:
3514 // Processing a Dex `int-to-double' instruction.
3515 locations->SetInAt(0, Location::RequiresRegister());
3516 locations->SetOut(Location::RequiresFpuRegister());
3517 break;
3518
3519 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00003520 // Processing a Dex `long-to-double' instruction.
3521 locations->SetInAt(0, Location::RequiresRegister());
3522 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01003523 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00003524 locations->AddTemp(Location::RequiresFpuRegister());
3525 break;
3526
Roland Levillaincff13742014-11-17 14:32:17 +00003527 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003528 // Processing a Dex `float-to-double' instruction.
3529 locations->SetInAt(0, Location::RequiresFpuRegister());
3530 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003531 break;
3532
3533 default:
3534 LOG(FATAL) << "Unexpected type conversion from " << input_type
3535 << " to " << result_type;
3536 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003537 break;
3538
3539 default:
3540 LOG(FATAL) << "Unexpected type conversion from " << input_type
3541 << " to " << result_type;
3542 }
3543}
3544
3545void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
3546 LocationSummary* locations = conversion->GetLocations();
3547 Location out = locations->Out();
3548 Location in = locations->InAt(0);
3549 Primitive::Type result_type = conversion->GetResultType();
3550 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003551 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00003552 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003553 case Primitive::kPrimByte:
3554 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003555 case Primitive::kPrimLong:
3556 // Type conversion from long to byte is a result of code transformations.
3557 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
3558 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003559 case Primitive::kPrimBoolean:
3560 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003561 case Primitive::kPrimShort:
3562 case Primitive::kPrimInt:
3563 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003564 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003565 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00003566 break;
3567
3568 default:
3569 LOG(FATAL) << "Unexpected type conversion from " << input_type
3570 << " to " << result_type;
3571 }
3572 break;
3573
Roland Levillain01a8d712014-11-14 16:27:39 +00003574 case Primitive::kPrimShort:
3575 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003576 case Primitive::kPrimLong:
3577 // Type conversion from long to short is a result of code transformations.
3578 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
3579 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003580 case Primitive::kPrimBoolean:
3581 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00003582 case Primitive::kPrimByte:
3583 case Primitive::kPrimInt:
3584 case Primitive::kPrimChar:
3585 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003586 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00003587 break;
3588
3589 default:
3590 LOG(FATAL) << "Unexpected type conversion from " << input_type
3591 << " to " << result_type;
3592 }
3593 break;
3594
Roland Levillain946e1432014-11-11 17:35:19 +00003595 case Primitive::kPrimInt:
3596 switch (input_type) {
3597 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00003598 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00003599 DCHECK(out.IsRegister());
3600 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003601 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00003602 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003603 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00003604 } else {
3605 DCHECK(in.IsConstant());
3606 DCHECK(in.GetConstant()->IsLongConstant());
3607 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003608 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00003609 }
3610 break;
3611
Roland Levillain3f8f9362014-12-02 17:45:01 +00003612 case Primitive::kPrimFloat: {
3613 // Processing a Dex `float-to-int' instruction.
3614 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01003615 __ vcvtis(temp, in.AsFpuRegister<SRegister>());
Roland Levillain3f8f9362014-12-02 17:45:01 +00003616 __ vmovrs(out.AsRegister<Register>(), temp);
3617 break;
3618 }
3619
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003620 case Primitive::kPrimDouble: {
3621 // Processing a Dex `double-to-int' instruction.
3622 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01003623 __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003624 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00003625 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003626 }
Roland Levillain946e1432014-11-11 17:35:19 +00003627
3628 default:
3629 LOG(FATAL) << "Unexpected type conversion from " << input_type
3630 << " to " << result_type;
3631 }
3632 break;
3633
Roland Levillaindff1f282014-11-05 14:15:05 +00003634 case Primitive::kPrimLong:
3635 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003636 case Primitive::kPrimBoolean:
3637 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00003638 case Primitive::kPrimByte:
3639 case Primitive::kPrimShort:
3640 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00003641 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003642 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00003643 DCHECK(out.IsRegisterPair());
3644 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003645 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00003646 // Sign extension.
3647 __ Asr(out.AsRegisterPairHigh<Register>(),
3648 out.AsRegisterPairLow<Register>(),
3649 31);
3650 break;
3651
3652 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00003653 // Processing a Dex `float-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003654 codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003655 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00003656 break;
3657
Roland Levillaindff1f282014-11-05 14:15:05 +00003658 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003659 // Processing a Dex `double-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003660 codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003661 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00003662 break;
3663
3664 default:
3665 LOG(FATAL) << "Unexpected type conversion from " << input_type
3666 << " to " << result_type;
3667 }
3668 break;
3669
Roland Levillain981e4542014-11-14 11:47:14 +00003670 case Primitive::kPrimChar:
3671 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003672 case Primitive::kPrimLong:
3673 // Type conversion from long to char is a result of code transformations.
3674 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
3675 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003676 case Primitive::kPrimBoolean:
3677 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00003678 case Primitive::kPrimByte:
3679 case Primitive::kPrimShort:
3680 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00003681 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003682 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00003683 break;
3684
3685 default:
3686 LOG(FATAL) << "Unexpected type conversion from " << input_type
3687 << " to " << result_type;
3688 }
3689 break;
3690
Roland Levillaindff1f282014-11-05 14:15:05 +00003691 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00003692 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003693 case Primitive::kPrimBoolean:
3694 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003695 case Primitive::kPrimByte:
3696 case Primitive::kPrimShort:
3697 case Primitive::kPrimInt:
3698 case Primitive::kPrimChar: {
3699 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003700 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
3701 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00003702 break;
3703 }
3704
Roland Levillain5b3ee562015-04-14 16:02:41 +01003705 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00003706 // Processing a Dex `long-to-float' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01003707 codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00003708 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00003709 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00003710
Roland Levillaincff13742014-11-17 14:32:17 +00003711 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003712 // Processing a Dex `double-to-float' instruction.
3713 __ vcvtsd(out.AsFpuRegister<SRegister>(),
3714 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00003715 break;
3716
3717 default:
3718 LOG(FATAL) << "Unexpected type conversion from " << input_type
3719 << " to " << result_type;
3720 };
3721 break;
3722
Roland Levillaindff1f282014-11-05 14:15:05 +00003723 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00003724 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003725 case Primitive::kPrimBoolean:
3726 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003727 case Primitive::kPrimByte:
3728 case Primitive::kPrimShort:
3729 case Primitive::kPrimInt:
3730 case Primitive::kPrimChar: {
3731 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003732 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00003733 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3734 out.AsFpuRegisterPairLow<SRegister>());
3735 break;
3736 }
3737
Roland Levillain647b9ed2014-11-27 12:06:00 +00003738 case Primitive::kPrimLong: {
3739 // Processing a Dex `long-to-double' instruction.
3740 Register low = in.AsRegisterPairLow<Register>();
3741 Register high = in.AsRegisterPairHigh<Register>();
3742 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
3743 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01003744 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00003745 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01003746 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
3747 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00003748
Roland Levillain682393c2015-04-14 15:57:52 +01003749 // temp_d = int-to-double(high)
3750 __ vmovsr(temp_s, high);
3751 __ vcvtdi(temp_d, temp_s);
3752 // constant_d = k2Pow32EncodingForDouble
3753 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
3754 // out_d = unsigned-to-double(low)
3755 __ vmovsr(out_s, low);
3756 __ vcvtdu(out_d, out_s);
3757 // out_d += temp_d * constant_d
3758 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00003759 break;
3760 }
3761
Roland Levillaincff13742014-11-17 14:32:17 +00003762 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003763 // Processing a Dex `float-to-double' instruction.
3764 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3765 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00003766 break;
3767
3768 default:
3769 LOG(FATAL) << "Unexpected type conversion from " << input_type
3770 << " to " << result_type;
3771 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003772 break;
3773
3774 default:
3775 LOG(FATAL) << "Unexpected type conversion from " << input_type
3776 << " to " << result_type;
3777 }
3778}
3779
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003780void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003781 LocationSummary* locations =
3782 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003783 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003784 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003785 locations->SetInAt(0, Location::RequiresRegister());
3786 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003787 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3788 break;
3789 }
3790
3791 case Primitive::kPrimLong: {
3792 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01003793 locations->SetInAt(1, ArmEncodableConstantOrRegister(add->InputAt(1), ADD));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003794 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003795 break;
3796 }
3797
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003798 case Primitive::kPrimFloat:
3799 case Primitive::kPrimDouble: {
3800 locations->SetInAt(0, Location::RequiresFpuRegister());
3801 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003802 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003803 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003804 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003805
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003806 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003807 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003808 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003809}
3810
3811void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
3812 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003813 Location out = locations->Out();
3814 Location first = locations->InAt(0);
3815 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003816 switch (add->GetResultType()) {
3817 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003818 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003819 __ add(out.AsRegister<Register>(),
3820 first.AsRegister<Register>(),
3821 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003822 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003823 __ AddConstant(out.AsRegister<Register>(),
3824 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003825 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003826 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003827 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003828
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003829 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01003830 if (second.IsConstant()) {
3831 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
3832 GenerateAddLongConst(out, first, value);
3833 } else {
3834 DCHECK(second.IsRegisterPair());
3835 __ adds(out.AsRegisterPairLow<Register>(),
3836 first.AsRegisterPairLow<Register>(),
3837 ShifterOperand(second.AsRegisterPairLow<Register>()));
3838 __ adc(out.AsRegisterPairHigh<Register>(),
3839 first.AsRegisterPairHigh<Register>(),
3840 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3841 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003842 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003843 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003844
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003845 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00003846 __ vadds(out.AsFpuRegister<SRegister>(),
3847 first.AsFpuRegister<SRegister>(),
3848 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003849 break;
3850
3851 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003852 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3853 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3854 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003855 break;
3856
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003857 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01003858 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00003859 }
3860}
3861
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003862void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003863 LocationSummary* locations =
3864 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003865 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003866 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003867 locations->SetInAt(0, Location::RequiresRegister());
3868 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00003869 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3870 break;
3871 }
3872
3873 case Primitive::kPrimLong: {
3874 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01003875 locations->SetInAt(1, ArmEncodableConstantOrRegister(sub->InputAt(1), SUB));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003876 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003877 break;
3878 }
Calin Juravle11351682014-10-23 15:38:15 +01003879 case Primitive::kPrimFloat:
3880 case Primitive::kPrimDouble: {
3881 locations->SetInAt(0, Location::RequiresFpuRegister());
3882 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003883 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003884 break;
Calin Juravle11351682014-10-23 15:38:15 +01003885 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003886 default:
Calin Juravle11351682014-10-23 15:38:15 +01003887 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003888 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003889}
3890
3891void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
3892 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01003893 Location out = locations->Out();
3894 Location first = locations->InAt(0);
3895 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003896 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003897 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01003898 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003899 __ sub(out.AsRegister<Register>(),
3900 first.AsRegister<Register>(),
3901 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003902 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003903 __ AddConstant(out.AsRegister<Register>(),
3904 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01003905 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003906 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003907 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003908 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003909
Calin Juravle11351682014-10-23 15:38:15 +01003910 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01003911 if (second.IsConstant()) {
3912 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
3913 GenerateAddLongConst(out, first, -value);
3914 } else {
3915 DCHECK(second.IsRegisterPair());
3916 __ subs(out.AsRegisterPairLow<Register>(),
3917 first.AsRegisterPairLow<Register>(),
3918 ShifterOperand(second.AsRegisterPairLow<Register>()));
3919 __ sbc(out.AsRegisterPairHigh<Register>(),
3920 first.AsRegisterPairHigh<Register>(),
3921 ShifterOperand(second.AsRegisterPairHigh<Register>()));
3922 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003923 break;
Calin Juravle11351682014-10-23 15:38:15 +01003924 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003925
Calin Juravle11351682014-10-23 15:38:15 +01003926 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00003927 __ vsubs(out.AsFpuRegister<SRegister>(),
3928 first.AsFpuRegister<SRegister>(),
3929 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003930 break;
Calin Juravle11351682014-10-23 15:38:15 +01003931 }
3932
3933 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003934 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3935 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
3936 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01003937 break;
3938 }
3939
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003940
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003941 default:
Calin Juravle11351682014-10-23 15:38:15 +01003942 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003943 }
3944}
3945
Calin Juravle34bacdf2014-10-07 20:23:36 +01003946void LocationsBuilderARM::VisitMul(HMul* mul) {
3947 LocationSummary* locations =
3948 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
3949 switch (mul->GetResultType()) {
3950 case Primitive::kPrimInt:
3951 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003952 locations->SetInAt(0, Location::RequiresRegister());
3953 locations->SetInAt(1, Location::RequiresRegister());
3954 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01003955 break;
3956 }
3957
Calin Juravleb5bfa962014-10-21 18:02:24 +01003958 case Primitive::kPrimFloat:
3959 case Primitive::kPrimDouble: {
3960 locations->SetInAt(0, Location::RequiresFpuRegister());
3961 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003962 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01003963 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01003964 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01003965
3966 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01003967 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01003968 }
3969}
3970
3971void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
3972 LocationSummary* locations = mul->GetLocations();
3973 Location out = locations->Out();
3974 Location first = locations->InAt(0);
3975 Location second = locations->InAt(1);
3976 switch (mul->GetResultType()) {
3977 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00003978 __ mul(out.AsRegister<Register>(),
3979 first.AsRegister<Register>(),
3980 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01003981 break;
3982 }
3983 case Primitive::kPrimLong: {
3984 Register out_hi = out.AsRegisterPairHigh<Register>();
3985 Register out_lo = out.AsRegisterPairLow<Register>();
3986 Register in1_hi = first.AsRegisterPairHigh<Register>();
3987 Register in1_lo = first.AsRegisterPairLow<Register>();
3988 Register in2_hi = second.AsRegisterPairHigh<Register>();
3989 Register in2_lo = second.AsRegisterPairLow<Register>();
3990
3991 // Extra checks to protect caused by the existence of R1_R2.
3992 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
3993 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
3994 DCHECK_NE(out_hi, in1_lo);
3995 DCHECK_NE(out_hi, in2_lo);
3996
3997 // input: in1 - 64 bits, in2 - 64 bits
3998 // output: out
3999 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
4000 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
4001 // parts: out.lo = (in1.lo * in2.lo)[31:0]
4002
4003 // IP <- in1.lo * in2.hi
4004 __ mul(IP, in1_lo, in2_hi);
4005 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
4006 __ mla(out_hi, in1_hi, in2_lo, IP);
4007 // out.lo <- (in1.lo * in2.lo)[31:0];
4008 __ umull(out_lo, IP, in1_lo, in2_lo);
4009 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
4010 __ add(out_hi, out_hi, ShifterOperand(IP));
4011 break;
4012 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01004013
4014 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004015 __ vmuls(out.AsFpuRegister<SRegister>(),
4016 first.AsFpuRegister<SRegister>(),
4017 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01004018 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01004019 }
4020
4021 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004022 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4023 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4024 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01004025 break;
4026 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01004027
4028 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01004029 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01004030 }
4031}
4032
Zheng Xuc6667102015-05-15 16:08:45 +08004033void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
4034 DCHECK(instruction->IsDiv() || instruction->IsRem());
4035 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4036
4037 LocationSummary* locations = instruction->GetLocations();
4038 Location second = locations->InAt(1);
4039 DCHECK(second.IsConstant());
4040
4041 Register out = locations->Out().AsRegister<Register>();
4042 Register dividend = locations->InAt(0).AsRegister<Register>();
4043 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4044 DCHECK(imm == 1 || imm == -1);
4045
4046 if (instruction->IsRem()) {
4047 __ LoadImmediate(out, 0);
4048 } else {
4049 if (imm == 1) {
4050 __ Mov(out, dividend);
4051 } else {
4052 __ rsb(out, dividend, ShifterOperand(0));
4053 }
4054 }
4055}
4056
4057void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
4058 DCHECK(instruction->IsDiv() || instruction->IsRem());
4059 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4060
4061 LocationSummary* locations = instruction->GetLocations();
4062 Location second = locations->InAt(1);
4063 DCHECK(second.IsConstant());
4064
4065 Register out = locations->Out().AsRegister<Register>();
4066 Register dividend = locations->InAt(0).AsRegister<Register>();
4067 Register temp = locations->GetTemp(0).AsRegister<Register>();
4068 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004069 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08004070 int ctz_imm = CTZ(abs_imm);
4071
4072 if (ctz_imm == 1) {
4073 __ Lsr(temp, dividend, 32 - ctz_imm);
4074 } else {
4075 __ Asr(temp, dividend, 31);
4076 __ Lsr(temp, temp, 32 - ctz_imm);
4077 }
4078 __ add(out, temp, ShifterOperand(dividend));
4079
4080 if (instruction->IsDiv()) {
4081 __ Asr(out, out, ctz_imm);
4082 if (imm < 0) {
4083 __ rsb(out, out, ShifterOperand(0));
4084 }
4085 } else {
4086 __ ubfx(out, out, 0, ctz_imm);
4087 __ sub(out, out, ShifterOperand(temp));
4088 }
4089}
4090
4091void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
4092 DCHECK(instruction->IsDiv() || instruction->IsRem());
4093 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4094
4095 LocationSummary* locations = instruction->GetLocations();
4096 Location second = locations->InAt(1);
4097 DCHECK(second.IsConstant());
4098
4099 Register out = locations->Out().AsRegister<Register>();
4100 Register dividend = locations->InAt(0).AsRegister<Register>();
4101 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4102 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4103 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4104
4105 int64_t magic;
4106 int shift;
4107 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
4108
4109 __ LoadImmediate(temp1, magic);
4110 __ smull(temp2, temp1, dividend, temp1);
4111
4112 if (imm > 0 && magic < 0) {
4113 __ add(temp1, temp1, ShifterOperand(dividend));
4114 } else if (imm < 0 && magic > 0) {
4115 __ sub(temp1, temp1, ShifterOperand(dividend));
4116 }
4117
4118 if (shift != 0) {
4119 __ Asr(temp1, temp1, shift);
4120 }
4121
4122 if (instruction->IsDiv()) {
4123 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
4124 } else {
4125 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
4126 // TODO: Strength reduction for mls.
4127 __ LoadImmediate(temp2, imm);
4128 __ mls(out, temp1, temp2, dividend);
4129 }
4130}
4131
4132void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
4133 DCHECK(instruction->IsDiv() || instruction->IsRem());
4134 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4135
4136 LocationSummary* locations = instruction->GetLocations();
4137 Location second = locations->InAt(1);
4138 DCHECK(second.IsConstant());
4139
4140 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4141 if (imm == 0) {
4142 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
4143 } else if (imm == 1 || imm == -1) {
4144 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004145 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004146 DivRemByPowerOfTwo(instruction);
4147 } else {
4148 DCHECK(imm <= -2 || imm >= 2);
4149 GenerateDivRemWithAnyConstant(instruction);
4150 }
4151}
4152
Calin Juravle7c4954d2014-10-28 16:57:40 +00004153void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004154 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4155 if (div->GetResultType() == Primitive::kPrimLong) {
4156 // pLdiv runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004157 call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004158 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
4159 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004160 } else if (div->GetResultType() == Primitive::kPrimInt &&
4161 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4162 // pIdivmod runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004163 call_kind = LocationSummary::kCallOnMainOnly;
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004164 }
4165
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004166 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
4167
Calin Juravle7c4954d2014-10-28 16:57:40 +00004168 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004169 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004170 if (div->InputAt(1)->IsConstant()) {
4171 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004172 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004173 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004174 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
4175 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004176 // No temp register required.
4177 } else {
4178 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004179 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004180 locations->AddTemp(Location::RequiresRegister());
4181 }
4182 }
4183 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004184 locations->SetInAt(0, Location::RequiresRegister());
4185 locations->SetInAt(1, Location::RequiresRegister());
4186 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4187 } else {
4188 InvokeRuntimeCallingConvention calling_convention;
4189 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4190 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004191 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004192 // we only need the former.
4193 locations->SetOut(Location::RegisterLocation(R0));
4194 }
Calin Juravled0d48522014-11-04 16:40:20 +00004195 break;
4196 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00004197 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004198 InvokeRuntimeCallingConvention calling_convention;
4199 locations->SetInAt(0, Location::RegisterPairLocation(
4200 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4201 locations->SetInAt(1, Location::RegisterPairLocation(
4202 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004203 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00004204 break;
4205 }
4206 case Primitive::kPrimFloat:
4207 case Primitive::kPrimDouble: {
4208 locations->SetInAt(0, Location::RequiresFpuRegister());
4209 locations->SetInAt(1, Location::RequiresFpuRegister());
4210 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4211 break;
4212 }
4213
4214 default:
4215 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4216 }
4217}
4218
4219void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
4220 LocationSummary* locations = div->GetLocations();
4221 Location out = locations->Out();
4222 Location first = locations->InAt(0);
4223 Location second = locations->InAt(1);
4224
4225 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004226 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004227 if (second.IsConstant()) {
4228 GenerateDivRemConstantIntegral(div);
4229 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004230 __ sdiv(out.AsRegister<Register>(),
4231 first.AsRegister<Register>(),
4232 second.AsRegister<Register>());
4233 } else {
4234 InvokeRuntimeCallingConvention calling_convention;
4235 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4236 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4237 DCHECK_EQ(R0, out.AsRegister<Register>());
4238
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004239 codegen_->InvokeRuntime(kQuickIdivmod, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004240 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004241 }
Calin Juravled0d48522014-11-04 16:40:20 +00004242 break;
4243 }
4244
Calin Juravle7c4954d2014-10-28 16:57:40 +00004245 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004246 InvokeRuntimeCallingConvention calling_convention;
4247 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
4248 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
4249 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
4250 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
4251 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004252 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004253
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004254 codegen_->InvokeRuntime(kQuickLdiv, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004255 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00004256 break;
4257 }
4258
4259 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004260 __ vdivs(out.AsFpuRegister<SRegister>(),
4261 first.AsFpuRegister<SRegister>(),
4262 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004263 break;
4264 }
4265
4266 case Primitive::kPrimDouble: {
4267 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4268 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4269 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
4270 break;
4271 }
4272
4273 default:
4274 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4275 }
4276}
4277
Calin Juravlebacfec32014-11-14 15:54:36 +00004278void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004279 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004280
4281 // Most remainders are implemented in the runtime.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004282 LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004283 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
4284 // sdiv will be replaced by other instruction sequence.
4285 call_kind = LocationSummary::kNoCall;
4286 } else if ((rem->GetResultType() == Primitive::kPrimInt)
4287 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004288 // Have hardware divide instruction for int, do it with three instructions.
4289 call_kind = LocationSummary::kNoCall;
4290 }
4291
Calin Juravlebacfec32014-11-14 15:54:36 +00004292 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
4293
Calin Juravled2ec87d2014-12-08 14:24:46 +00004294 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004295 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004296 if (rem->InputAt(1)->IsConstant()) {
4297 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004298 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004299 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004300 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
4301 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004302 // No temp register required.
4303 } else {
4304 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004305 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004306 locations->AddTemp(Location::RequiresRegister());
4307 }
4308 }
4309 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004310 locations->SetInAt(0, Location::RequiresRegister());
4311 locations->SetInAt(1, Location::RequiresRegister());
4312 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4313 locations->AddTemp(Location::RequiresRegister());
4314 } else {
4315 InvokeRuntimeCallingConvention calling_convention;
4316 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4317 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004318 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004319 // we only need the latter.
4320 locations->SetOut(Location::RegisterLocation(R1));
4321 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004322 break;
4323 }
4324 case Primitive::kPrimLong: {
4325 InvokeRuntimeCallingConvention calling_convention;
4326 locations->SetInAt(0, Location::RegisterPairLocation(
4327 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4328 locations->SetInAt(1, Location::RegisterPairLocation(
4329 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4330 // The runtime helper puts the output in R2,R3.
4331 locations->SetOut(Location::RegisterPairLocation(R2, R3));
4332 break;
4333 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00004334 case Primitive::kPrimFloat: {
4335 InvokeRuntimeCallingConvention calling_convention;
4336 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
4337 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
4338 locations->SetOut(Location::FpuRegisterLocation(S0));
4339 break;
4340 }
4341
Calin Juravlebacfec32014-11-14 15:54:36 +00004342 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004343 InvokeRuntimeCallingConvention calling_convention;
4344 locations->SetInAt(0, Location::FpuRegisterPairLocation(
4345 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
4346 locations->SetInAt(1, Location::FpuRegisterPairLocation(
4347 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
4348 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00004349 break;
4350 }
4351
4352 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004353 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004354 }
4355}
4356
4357void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
4358 LocationSummary* locations = rem->GetLocations();
4359 Location out = locations->Out();
4360 Location first = locations->InAt(0);
4361 Location second = locations->InAt(1);
4362
Calin Juravled2ec87d2014-12-08 14:24:46 +00004363 Primitive::Type type = rem->GetResultType();
4364 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004365 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004366 if (second.IsConstant()) {
4367 GenerateDivRemConstantIntegral(rem);
4368 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004369 Register reg1 = first.AsRegister<Register>();
4370 Register reg2 = second.AsRegister<Register>();
4371 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004372
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004373 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004374 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004375 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004376 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004377 } else {
4378 InvokeRuntimeCallingConvention calling_convention;
4379 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4380 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4381 DCHECK_EQ(R1, out.AsRegister<Register>());
4382
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004383 codegen_->InvokeRuntime(kQuickIdivmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004384 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004385 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004386 break;
4387 }
4388
4389 case Primitive::kPrimLong: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004390 codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004391 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004392 break;
4393 }
4394
Calin Juravled2ec87d2014-12-08 14:24:46 +00004395 case Primitive::kPrimFloat: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004396 codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004397 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00004398 break;
4399 }
4400
Calin Juravlebacfec32014-11-14 15:54:36 +00004401 case Primitive::kPrimDouble: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004402 codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004403 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004404 break;
4405 }
4406
4407 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004408 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004409 }
4410}
4411
Calin Juravled0d48522014-11-04 16:40:20 +00004412void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004413 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004414 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00004415}
4416
4417void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01004418 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00004419 codegen_->AddSlowPath(slow_path);
4420
4421 LocationSummary* locations = instruction->GetLocations();
4422 Location value = locations->InAt(0);
4423
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004424 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00004425 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06004426 case Primitive::kPrimByte:
4427 case Primitive::kPrimChar:
4428 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004429 case Primitive::kPrimInt: {
4430 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004431 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004432 } else {
4433 DCHECK(value.IsConstant()) << value;
4434 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
4435 __ b(slow_path->GetEntryLabel());
4436 }
4437 }
4438 break;
4439 }
4440 case Primitive::kPrimLong: {
4441 if (value.IsRegisterPair()) {
4442 __ orrs(IP,
4443 value.AsRegisterPairLow<Register>(),
4444 ShifterOperand(value.AsRegisterPairHigh<Register>()));
4445 __ b(slow_path->GetEntryLabel(), EQ);
4446 } else {
4447 DCHECK(value.IsConstant()) << value;
4448 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4449 __ b(slow_path->GetEntryLabel());
4450 }
4451 }
4452 break;
4453 default:
4454 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
4455 }
4456 }
Calin Juravled0d48522014-11-04 16:40:20 +00004457}
4458
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004459void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
4460 Register in = locations->InAt(0).AsRegister<Register>();
4461 Location rhs = locations->InAt(1);
4462 Register out = locations->Out().AsRegister<Register>();
4463
4464 if (rhs.IsConstant()) {
4465 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
4466 // so map all rotations to a +ve. equivalent in that range.
4467 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
4468 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
4469 if (rot) {
4470 // Rotate, mapping left rotations to right equivalents if necessary.
4471 // (e.g. left by 2 bits == right by 30.)
4472 __ Ror(out, in, rot);
4473 } else if (out != in) {
4474 __ Mov(out, in);
4475 }
4476 } else {
4477 __ Ror(out, in, rhs.AsRegister<Register>());
4478 }
4479}
4480
4481// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
4482// rotates by swapping input regs (effectively rotating by the first 32-bits of
4483// a larger rotation) or flipping direction (thus treating larger right/left
4484// rotations as sub-word sized rotations in the other direction) as appropriate.
Anton Kirilov6f644202017-02-27 18:29:45 +00004485void InstructionCodeGeneratorARM::HandleLongRotate(HRor* ror) {
4486 LocationSummary* locations = ror->GetLocations();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004487 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
4488 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
4489 Location rhs = locations->InAt(1);
4490 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
4491 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
4492
4493 if (rhs.IsConstant()) {
4494 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
4495 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00004496 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004497 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
4498 // logic below to a simple pair of binary orr.
4499 // (e.g. 34 bits == in_reg swap + 2 bits right.)
4500 if (rot >= kArmBitsPerWord) {
4501 rot -= kArmBitsPerWord;
4502 std::swap(in_reg_hi, in_reg_lo);
4503 }
4504 // Rotate, or mov to out for zero or word size rotations.
4505 if (rot != 0u) {
4506 __ Lsr(out_reg_hi, in_reg_hi, rot);
4507 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
4508 __ Lsr(out_reg_lo, in_reg_lo, rot);
4509 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
4510 } else {
4511 __ Mov(out_reg_lo, in_reg_lo);
4512 __ Mov(out_reg_hi, in_reg_hi);
4513 }
4514 } else {
4515 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
4516 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
4517 Label end;
4518 Label shift_by_32_plus_shift_right;
Anton Kirilov6f644202017-02-27 18:29:45 +00004519 Label* final_label = codegen_->GetFinalLabel(ror, &end);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004520
4521 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
4522 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
4523 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
4524 __ b(&shift_by_32_plus_shift_right, CC);
4525
4526 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
4527 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
4528 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
4529 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4530 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4531 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4532 __ Lsr(shift_left, in_reg_hi, shift_right);
4533 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
Anton Kirilov6f644202017-02-27 18:29:45 +00004534 __ b(final_label);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004535
4536 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
4537 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
4538 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
4539 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
4540 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4541 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4542 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4543 __ Lsl(shift_right, in_reg_hi, shift_left);
4544 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
4545
Anton Kirilov6f644202017-02-27 18:29:45 +00004546 if (end.IsLinked()) {
4547 __ Bind(&end);
4548 }
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004549 }
4550}
Roland Levillain22c49222016-03-18 14:04:28 +00004551
4552void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004553 LocationSummary* locations =
4554 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
4555 switch (ror->GetResultType()) {
4556 case Primitive::kPrimInt: {
4557 locations->SetInAt(0, Location::RequiresRegister());
4558 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
4559 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4560 break;
4561 }
4562 case Primitive::kPrimLong: {
4563 locations->SetInAt(0, Location::RequiresRegister());
4564 if (ror->InputAt(1)->IsConstant()) {
4565 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
4566 } else {
4567 locations->SetInAt(1, Location::RequiresRegister());
4568 locations->AddTemp(Location::RequiresRegister());
4569 locations->AddTemp(Location::RequiresRegister());
4570 }
4571 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4572 break;
4573 }
4574 default:
4575 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4576 }
4577}
4578
Roland Levillain22c49222016-03-18 14:04:28 +00004579void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004580 LocationSummary* locations = ror->GetLocations();
4581 Primitive::Type type = ror->GetResultType();
4582 switch (type) {
4583 case Primitive::kPrimInt: {
4584 HandleIntegerRotate(locations);
4585 break;
4586 }
4587 case Primitive::kPrimLong: {
Anton Kirilov6f644202017-02-27 18:29:45 +00004588 HandleLongRotate(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004589 break;
4590 }
4591 default:
4592 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00004593 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004594 }
4595}
4596
Calin Juravle9aec02f2014-11-18 23:06:35 +00004597void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
4598 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4599
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004600 LocationSummary* locations =
4601 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004602
4603 switch (op->GetResultType()) {
4604 case Primitive::kPrimInt: {
4605 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004606 if (op->InputAt(1)->IsConstant()) {
4607 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4608 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4609 } else {
4610 locations->SetInAt(1, Location::RequiresRegister());
4611 // Make the output overlap, as it will be used to hold the masked
4612 // second input.
4613 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4614 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004615 break;
4616 }
4617 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004618 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004619 if (op->InputAt(1)->IsConstant()) {
4620 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4621 // For simplicity, use kOutputOverlap even though we only require that low registers
4622 // don't clash with high registers which the register allocator currently guarantees.
4623 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4624 } else {
4625 locations->SetInAt(1, Location::RequiresRegister());
4626 locations->AddTemp(Location::RequiresRegister());
4627 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4628 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004629 break;
4630 }
4631 default:
4632 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
4633 }
4634}
4635
4636void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
4637 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4638
4639 LocationSummary* locations = op->GetLocations();
4640 Location out = locations->Out();
4641 Location first = locations->InAt(0);
4642 Location second = locations->InAt(1);
4643
4644 Primitive::Type type = op->GetResultType();
4645 switch (type) {
4646 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004647 Register out_reg = out.AsRegister<Register>();
4648 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004649 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004650 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00004651 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00004652 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00004653 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01004654 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004655 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01004656 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004657 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01004658 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004659 }
4660 } else {
4661 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00004662 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00004663 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00004664 __ Mov(out_reg, first_reg);
4665 } else if (op->IsShl()) {
4666 __ Lsl(out_reg, first_reg, shift_value);
4667 } else if (op->IsShr()) {
4668 __ Asr(out_reg, first_reg, shift_value);
4669 } else {
4670 __ Lsr(out_reg, first_reg, shift_value);
4671 }
4672 }
4673 break;
4674 }
4675 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004676 Register o_h = out.AsRegisterPairHigh<Register>();
4677 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004678
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004679 Register high = first.AsRegisterPairHigh<Register>();
4680 Register low = first.AsRegisterPairLow<Register>();
4681
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004682 if (second.IsRegister()) {
4683 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004684
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004685 Register second_reg = second.AsRegister<Register>();
4686
4687 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004688 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004689 // Shift the high part
4690 __ Lsl(o_h, high, o_l);
4691 // Shift the low part and `or` what overflew on the high part
4692 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
4693 __ Lsr(temp, low, temp);
4694 __ orr(o_h, o_h, ShifterOperand(temp));
4695 // If the shift is > 32 bits, override the high part
4696 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
4697 __ it(PL);
4698 __ Lsl(o_h, low, temp, PL);
4699 // Shift the low part
4700 __ Lsl(o_l, low, o_l);
4701 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004702 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004703 // Shift the low part
4704 __ Lsr(o_l, low, o_h);
4705 // Shift the high part and `or` what underflew on the low part
4706 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
4707 __ Lsl(temp, high, temp);
4708 __ orr(o_l, o_l, ShifterOperand(temp));
4709 // If the shift is > 32 bits, override the low part
4710 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
4711 __ it(PL);
4712 __ Asr(o_l, high, temp, PL);
4713 // Shift the high part
4714 __ Asr(o_h, high, o_h);
4715 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00004716 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004717 // same as Shr except we use `Lsr`s and not `Asr`s
4718 __ Lsr(o_l, low, o_h);
4719 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
4720 __ Lsl(temp, high, temp);
4721 __ orr(o_l, o_l, ShifterOperand(temp));
4722 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
4723 __ it(PL);
4724 __ Lsr(o_l, high, temp, PL);
4725 __ Lsr(o_h, high, o_h);
4726 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004727 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004728 // Register allocator doesn't create partial overlap.
4729 DCHECK_NE(o_l, high);
4730 DCHECK_NE(o_h, low);
4731 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00004732 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004733 if (shift_value > 32) {
4734 if (op->IsShl()) {
4735 __ Lsl(o_h, low, shift_value - 32);
4736 __ LoadImmediate(o_l, 0);
4737 } else if (op->IsShr()) {
4738 __ Asr(o_l, high, shift_value - 32);
4739 __ Asr(o_h, high, 31);
4740 } else {
4741 __ Lsr(o_l, high, shift_value - 32);
4742 __ LoadImmediate(o_h, 0);
4743 }
4744 } else if (shift_value == 32) {
4745 if (op->IsShl()) {
4746 __ mov(o_h, ShifterOperand(low));
4747 __ LoadImmediate(o_l, 0);
4748 } else if (op->IsShr()) {
4749 __ mov(o_l, ShifterOperand(high));
4750 __ Asr(o_h, high, 31);
4751 } else {
4752 __ mov(o_l, ShifterOperand(high));
4753 __ LoadImmediate(o_h, 0);
4754 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00004755 } else if (shift_value == 1) {
4756 if (op->IsShl()) {
4757 __ Lsls(o_l, low, 1);
4758 __ adc(o_h, high, ShifterOperand(high));
4759 } else if (op->IsShr()) {
4760 __ Asrs(o_h, high, 1);
4761 __ Rrx(o_l, low);
4762 } else {
4763 __ Lsrs(o_h, high, 1);
4764 __ Rrx(o_l, low);
4765 }
4766 } else {
4767 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004768 if (op->IsShl()) {
4769 __ Lsl(o_h, high, shift_value);
4770 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
4771 __ Lsl(o_l, low, shift_value);
4772 } else if (op->IsShr()) {
4773 __ Lsr(o_l, low, shift_value);
4774 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
4775 __ Asr(o_h, high, shift_value);
4776 } else {
4777 __ Lsr(o_l, low, shift_value);
4778 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
4779 __ Lsr(o_h, high, shift_value);
4780 }
4781 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004782 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004783 break;
4784 }
4785 default:
4786 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004787 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00004788 }
4789}
4790
4791void LocationsBuilderARM::VisitShl(HShl* shl) {
4792 HandleShift(shl);
4793}
4794
4795void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
4796 HandleShift(shl);
4797}
4798
4799void LocationsBuilderARM::VisitShr(HShr* shr) {
4800 HandleShift(shr);
4801}
4802
4803void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
4804 HandleShift(shr);
4805}
4806
4807void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
4808 HandleShift(ushr);
4809}
4810
4811void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
4812 HandleShift(ushr);
4813}
4814
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004815void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004816 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004817 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
David Brazdil6de19382016-01-08 17:37:10 +00004818 if (instruction->IsStringAlloc()) {
4819 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
4820 } else {
4821 InvokeRuntimeCallingConvention calling_convention;
4822 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00004823 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004824 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004825}
4826
4827void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004828 // Note: if heap poisoning is enabled, the entry point takes cares
4829 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00004830 if (instruction->IsStringAlloc()) {
4831 // String is allocated through StringFactory. Call NewEmptyString entry point.
4832 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07004833 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00004834 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
4835 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
4836 __ blx(LR);
4837 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4838 } else {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004839 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00004840 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00004841 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01004842}
4843
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004844void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
4845 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004846 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004847 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004848 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004849 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4850 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004851}
4852
4853void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01004854 // Note: if heap poisoning is enabled, the entry point takes cares
4855 // of poisoning the reference.
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00004856 QuickEntrypointEnum entrypoint =
4857 CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
4858 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00004859 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00004860 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01004861}
4862
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004863void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004864 LocationSummary* locations =
4865 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004866 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4867 if (location.IsStackSlot()) {
4868 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4869 } else if (location.IsDoubleStackSlot()) {
4870 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004871 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01004872 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004873}
4874
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004875void InstructionCodeGeneratorARM::VisitParameterValue(
4876 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004877 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004878}
4879
4880void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
4881 LocationSummary* locations =
4882 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4883 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4884}
4885
4886void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
4887 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004888}
4889
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004890void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004891 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004892 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004893 locations->SetInAt(0, Location::RequiresRegister());
4894 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004895}
4896
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004897void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
4898 LocationSummary* locations = not_->GetLocations();
4899 Location out = locations->Out();
4900 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00004901 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004902 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00004903 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004904 break;
4905
4906 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01004907 __ mvn(out.AsRegisterPairLow<Register>(),
4908 ShifterOperand(in.AsRegisterPairLow<Register>()));
4909 __ mvn(out.AsRegisterPairHigh<Register>(),
4910 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01004911 break;
4912
4913 default:
4914 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
4915 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01004916}
4917
David Brazdil66d126e2015-04-03 16:02:44 +01004918void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
4919 LocationSummary* locations =
4920 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
4921 locations->SetInAt(0, Location::RequiresRegister());
4922 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4923}
4924
4925void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01004926 LocationSummary* locations = bool_not->GetLocations();
4927 Location out = locations->Out();
4928 Location in = locations->InAt(0);
4929 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
4930}
4931
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004932void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004933 LocationSummary* locations =
4934 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00004935 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00004936 case Primitive::kPrimBoolean:
4937 case Primitive::kPrimByte:
4938 case Primitive::kPrimShort:
4939 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08004940 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00004941 case Primitive::kPrimLong: {
4942 locations->SetInAt(0, Location::RequiresRegister());
4943 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004944 // Output overlaps because it is written before doing the low comparison.
4945 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00004946 break;
4947 }
4948 case Primitive::kPrimFloat:
4949 case Primitive::kPrimDouble: {
4950 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01004951 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00004952 locations->SetOut(Location::RequiresRegister());
4953 break;
4954 }
4955 default:
4956 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
4957 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004958}
4959
4960void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004961 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004962 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00004963 Location left = locations->InAt(0);
4964 Location right = locations->InAt(1);
4965
Vladimir Markocf93a5c2015-06-16 11:33:24 +00004966 Label less, greater, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00004967 Label* final_label = codegen_->GetFinalLabel(compare, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00004968 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00004969 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00004970 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00004971 case Primitive::kPrimBoolean:
4972 case Primitive::kPrimByte:
4973 case Primitive::kPrimShort:
4974 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08004975 case Primitive::kPrimInt: {
4976 __ LoadImmediate(out, 0);
4977 __ cmp(left.AsRegister<Register>(),
4978 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
4979 less_cond = LT;
4980 break;
4981 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004982 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004983 __ cmp(left.AsRegisterPairHigh<Register>(),
4984 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01004985 __ b(&less, LT);
4986 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01004987 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00004988 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004989 __ cmp(left.AsRegisterPairLow<Register>(),
4990 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00004991 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00004992 break;
4993 }
4994 case Primitive::kPrimFloat:
4995 case Primitive::kPrimDouble: {
4996 __ LoadImmediate(out, 0);
Donghui Bai426b49c2016-11-08 14:55:38 +08004997 GenerateVcmp(compare, codegen_);
Calin Juravleddb7df22014-11-25 20:56:51 +00004998 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00004999 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005000 break;
5001 }
5002 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00005003 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00005004 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005005 }
Aart Bika19616e2016-02-01 18:57:58 -08005006
Anton Kirilov6f644202017-02-27 18:29:45 +00005007 __ b(final_label, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00005008 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00005009
5010 __ Bind(&greater);
5011 __ LoadImmediate(out, 1);
Anton Kirilov6f644202017-02-27 18:29:45 +00005012 __ b(final_label);
Calin Juravleddb7df22014-11-25 20:56:51 +00005013
5014 __ Bind(&less);
5015 __ LoadImmediate(out, -1);
5016
Anton Kirilov6f644202017-02-27 18:29:45 +00005017 if (done.IsLinked()) {
5018 __ Bind(&done);
5019 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005020}
5021
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005022void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005023 LocationSummary* locations =
5024 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01005025 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01005026 locations->SetInAt(i, Location::Any());
5027 }
5028 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005029}
5030
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005031void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005032 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005033}
5034
Roland Levillainc9285912015-12-18 10:38:42 +00005035void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
5036 // TODO (ported from quick): revisit ARM barrier kinds.
5037 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00005038 switch (kind) {
5039 case MemBarrierKind::kAnyStore:
5040 case MemBarrierKind::kLoadAny:
5041 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005042 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00005043 break;
5044 }
5045 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005046 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00005047 break;
5048 }
5049 default:
5050 LOG(FATAL) << "Unexpected memory barrier " << kind;
5051 }
Kenny Root1d8199d2015-06-02 11:01:10 -07005052 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00005053}
5054
5055void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
5056 uint32_t offset,
5057 Register out_lo,
5058 Register out_hi) {
5059 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005060 // Ensure `out_lo` is different from `addr`, so that loading
5061 // `offset` into `out_lo` does not clutter `addr`.
5062 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00005063 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005064 __ add(IP, addr, ShifterOperand(out_lo));
5065 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005066 }
5067 __ ldrexd(out_lo, out_hi, addr);
5068}
5069
5070void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
5071 uint32_t offset,
5072 Register value_lo,
5073 Register value_hi,
5074 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00005075 Register temp2,
5076 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005077 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00005078 if (offset != 0) {
5079 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005080 __ add(IP, addr, ShifterOperand(temp1));
5081 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005082 }
5083 __ Bind(&fail);
5084 // We need a load followed by store. (The address used in a STREX instruction must
5085 // be the same as the address in the most recently executed LDREX instruction.)
5086 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00005087 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005088 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005089 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00005090}
5091
5092void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5093 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5094
Nicolas Geoffray39468442014-09-02 15:17:15 +01005095 LocationSummary* locations =
5096 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005097 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005098
Calin Juravle52c48962014-12-16 17:02:57 +00005099 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005100 if (Primitive::IsFloatingPointType(field_type)) {
5101 locations->SetInAt(1, Location::RequiresFpuRegister());
5102 } else {
5103 locations->SetInAt(1, Location::RequiresRegister());
5104 }
5105
Calin Juravle52c48962014-12-16 17:02:57 +00005106 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00005107 bool generate_volatile = field_info.IsVolatile()
5108 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005109 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01005110 bool needs_write_barrier =
5111 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005112 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00005113 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01005114 if (needs_write_barrier) {
5115 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005116 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005117 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005118 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005119 // - registers need to be consecutive
5120 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005121 // We don't test for ARM yet, and the assertion makes sure that we
5122 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005123 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5124
5125 locations->AddTemp(Location::RequiresRegister());
5126 locations->AddTemp(Location::RequiresRegister());
5127 if (field_type == Primitive::kPrimDouble) {
5128 // For doubles we need two more registers to copy the value.
5129 locations->AddTemp(Location::RegisterLocation(R2));
5130 locations->AddTemp(Location::RegisterLocation(R3));
5131 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005132 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005133}
5134
Calin Juravle52c48962014-12-16 17:02:57 +00005135void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005136 const FieldInfo& field_info,
5137 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00005138 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5139
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005140 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00005141 Register base = locations->InAt(0).AsRegister<Register>();
5142 Location value = locations->InAt(1);
5143
5144 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005145 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005146 Primitive::Type field_type = field_info.GetFieldType();
5147 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01005148 bool needs_write_barrier =
5149 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00005150
5151 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005152 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00005153 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005154
5155 switch (field_type) {
5156 case Primitive::kPrimBoolean:
5157 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00005158 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005159 break;
5160 }
5161
5162 case Primitive::kPrimShort:
5163 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00005164 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005165 break;
5166 }
5167
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005168 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005169 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01005170 if (kPoisonHeapReferences && needs_write_barrier) {
5171 // Note that in the case where `value` is a null reference,
5172 // we do not enter this block, as a null reference does not
5173 // need poisoning.
5174 DCHECK_EQ(field_type, Primitive::kPrimNot);
5175 Register temp = locations->GetTemp(0).AsRegister<Register>();
5176 __ Mov(temp, value.AsRegister<Register>());
5177 __ PoisonHeapReference(temp);
5178 __ StoreToOffset(kStoreWord, temp, base, offset);
5179 } else {
5180 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
5181 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005182 break;
5183 }
5184
5185 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00005186 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005187 GenerateWideAtomicStore(base, offset,
5188 value.AsRegisterPairLow<Register>(),
5189 value.AsRegisterPairHigh<Register>(),
5190 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005191 locations->GetTemp(1).AsRegister<Register>(),
5192 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005193 } else {
5194 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005195 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005196 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005197 break;
5198 }
5199
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005200 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00005201 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005202 break;
5203 }
5204
5205 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005206 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005207 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005208 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
5209 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
5210
5211 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
5212
5213 GenerateWideAtomicStore(base, offset,
5214 value_reg_lo,
5215 value_reg_hi,
5216 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005217 locations->GetTemp(3).AsRegister<Register>(),
5218 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005219 } else {
5220 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005221 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005222 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005223 break;
5224 }
5225
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005226 case Primitive::kPrimVoid:
5227 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005228 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005229 }
Calin Juravle52c48962014-12-16 17:02:57 +00005230
Calin Juravle77520bc2015-01-12 18:45:46 +00005231 // Longs and doubles are handled in the switch.
5232 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
5233 codegen_->MaybeRecordImplicitNullCheck(instruction);
5234 }
5235
5236 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
5237 Register temp = locations->GetTemp(0).AsRegister<Register>();
5238 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005239 codegen_->MarkGCCard(
5240 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00005241 }
5242
Calin Juravle52c48962014-12-16 17:02:57 +00005243 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005244 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00005245 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005246}
5247
Calin Juravle52c48962014-12-16 17:02:57 +00005248void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
5249 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00005250
5251 bool object_field_get_with_read_barrier =
5252 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005253 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00005254 new (GetGraph()->GetArena()) LocationSummary(instruction,
5255 object_field_get_with_read_barrier ?
5256 LocationSummary::kCallOnSlowPath :
5257 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005258 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005259 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005260 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005261 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00005262
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005263 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00005264 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005265 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00005266 // The output overlaps in case of volatile long: we don't want the
5267 // code generated by GenerateWideAtomicLoad to overwrite the
5268 // object's location. Likewise, in the case of an object field get
5269 // with read barriers enabled, we do not want the load to overwrite
5270 // the object's location, as we need it to emit the read barrier.
5271 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
5272 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01005273
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005274 if (Primitive::IsFloatingPointType(instruction->GetType())) {
5275 locations->SetOut(Location::RequiresFpuRegister());
5276 } else {
5277 locations->SetOut(Location::RequiresRegister(),
5278 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
5279 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005280 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00005281 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005282 // - registers need to be consecutive
5283 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005284 // We don't test for ARM yet, and the assertion makes sure that we
5285 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005286 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5287 locations->AddTemp(Location::RequiresRegister());
5288 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00005289 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
5290 // We need a temporary register for the read barrier marking slow
5291 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
5292 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00005293 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005294}
5295
Vladimir Marko37dd80d2016-08-01 17:41:45 +01005296Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
5297 DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
5298 << input->GetType();
5299 if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
5300 (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
5301 return Location::ConstantLocation(input->AsConstant());
5302 } else {
5303 return Location::RequiresFpuRegister();
5304 }
5305}
5306
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005307Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
5308 Opcode opcode) {
5309 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
5310 if (constant->IsConstant() &&
5311 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
5312 return Location::ConstantLocation(constant->AsConstant());
5313 }
5314 return Location::RequiresRegister();
5315}
5316
5317bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
5318 Opcode opcode) {
5319 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
5320 if (Primitive::Is64BitType(input_cst->GetType())) {
Vladimir Marko59751a72016-08-05 14:37:27 +01005321 Opcode high_opcode = opcode;
5322 SetCc low_set_cc = kCcDontCare;
5323 switch (opcode) {
5324 case SUB:
5325 // Flip the operation to an ADD.
5326 value = -value;
5327 opcode = ADD;
5328 FALLTHROUGH_INTENDED;
5329 case ADD:
5330 if (Low32Bits(value) == 0u) {
5331 return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
5332 }
5333 high_opcode = ADC;
5334 low_set_cc = kCcSet;
5335 break;
5336 default:
5337 break;
5338 }
5339 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
5340 CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005341 } else {
5342 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
5343 }
5344}
5345
Vladimir Marko59751a72016-08-05 14:37:27 +01005346bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
5347 Opcode opcode,
5348 SetCc set_cc) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005349 ShifterOperand so;
5350 ArmAssembler* assembler = codegen_->GetAssembler();
Vladimir Marko59751a72016-08-05 14:37:27 +01005351 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005352 return true;
5353 }
5354 Opcode neg_opcode = kNoOperand;
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005355 uint32_t neg_value = 0;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005356 switch (opcode) {
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005357 case AND: neg_opcode = BIC; neg_value = ~value; break;
5358 case ORR: neg_opcode = ORN; neg_value = ~value; break;
5359 case ADD: neg_opcode = SUB; neg_value = -value; break;
5360 case ADC: neg_opcode = SBC; neg_value = ~value; break;
5361 case SUB: neg_opcode = ADD; neg_value = -value; break;
5362 case SBC: neg_opcode = ADC; neg_value = ~value; break;
5363 case MOV: neg_opcode = MVN; neg_value = ~value; break;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005364 default:
5365 return false;
5366 }
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005367
5368 if (assembler->ShifterOperandCanHold(kNoRegister,
5369 kNoRegister,
5370 neg_opcode,
5371 neg_value,
5372 set_cc,
5373 &so)) {
5374 return true;
5375 }
5376
5377 return opcode == AND && IsPowerOfTwo(value + 1);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005378}
5379
Calin Juravle52c48962014-12-16 17:02:57 +00005380void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
5381 const FieldInfo& field_info) {
5382 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005383
Calin Juravle52c48962014-12-16 17:02:57 +00005384 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005385 Location base_loc = locations->InAt(0);
5386 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00005387 Location out = locations->Out();
5388 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005389 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005390 Primitive::Type field_type = field_info.GetFieldType();
5391 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5392
5393 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00005394 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00005395 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005396 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005397
Roland Levillainc9285912015-12-18 10:38:42 +00005398 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00005399 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005400 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005401
Roland Levillainc9285912015-12-18 10:38:42 +00005402 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00005403 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005404 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005405
Roland Levillainc9285912015-12-18 10:38:42 +00005406 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00005407 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005408 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005409
5410 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00005411 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005412 break;
Roland Levillainc9285912015-12-18 10:38:42 +00005413
5414 case Primitive::kPrimNot: {
5415 // /* HeapReference<Object> */ out = *(base + offset)
5416 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5417 Location temp_loc = locations->GetTemp(0);
5418 // Note that a potential implicit null check is handled in this
5419 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
5420 codegen_->GenerateFieldLoadWithBakerReadBarrier(
5421 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
5422 if (is_volatile) {
5423 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5424 }
5425 } else {
5426 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
5427 codegen_->MaybeRecordImplicitNullCheck(instruction);
5428 if (is_volatile) {
5429 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5430 }
5431 // If read barriers are enabled, emit read barriers other than
5432 // Baker's using a slow path (and also unpoison the loaded
5433 // reference, if heap poisoning is enabled).
5434 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
5435 }
5436 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005437 }
5438
Roland Levillainc9285912015-12-18 10:38:42 +00005439 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00005440 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005441 GenerateWideAtomicLoad(base, offset,
5442 out.AsRegisterPairLow<Register>(),
5443 out.AsRegisterPairHigh<Register>());
5444 } else {
5445 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
5446 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005447 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005448
Roland Levillainc9285912015-12-18 10:38:42 +00005449 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00005450 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005451 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005452
5453 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005454 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005455 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005456 Register lo = locations->GetTemp(0).AsRegister<Register>();
5457 Register hi = locations->GetTemp(1).AsRegister<Register>();
5458 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00005459 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005460 __ vmovdrr(out_reg, lo, hi);
5461 } else {
5462 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005463 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005464 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005465 break;
5466 }
5467
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005468 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00005469 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005470 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005471 }
Calin Juravle52c48962014-12-16 17:02:57 +00005472
Roland Levillainc9285912015-12-18 10:38:42 +00005473 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
5474 // Potential implicit null checks, in the case of reference or
5475 // double fields, are handled in the previous switch statement.
5476 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00005477 codegen_->MaybeRecordImplicitNullCheck(instruction);
5478 }
5479
Calin Juravle52c48962014-12-16 17:02:57 +00005480 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005481 if (field_type == Primitive::kPrimNot) {
5482 // Memory barriers, in the case of references, are also handled
5483 // in the previous switch statement.
5484 } else {
5485 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5486 }
Roland Levillain4d027112015-07-01 15:41:14 +01005487 }
Calin Juravle52c48962014-12-16 17:02:57 +00005488}
5489
5490void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
5491 HandleFieldSet(instruction, instruction->GetFieldInfo());
5492}
5493
5494void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005495 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00005496}
5497
5498void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5499 HandleFieldGet(instruction, instruction->GetFieldInfo());
5500}
5501
5502void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5503 HandleFieldGet(instruction, instruction->GetFieldInfo());
5504}
5505
5506void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5507 HandleFieldGet(instruction, instruction->GetFieldInfo());
5508}
5509
5510void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5511 HandleFieldGet(instruction, instruction->GetFieldInfo());
5512}
5513
5514void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5515 HandleFieldSet(instruction, instruction->GetFieldInfo());
5516}
5517
5518void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005519 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005520}
5521
Calin Juravlee460d1d2015-09-29 04:52:17 +01005522void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
5523 HUnresolvedInstanceFieldGet* instruction) {
5524 FieldAccessCallingConventionARM calling_convention;
5525 codegen_->CreateUnresolvedFieldLocationSummary(
5526 instruction, instruction->GetFieldType(), calling_convention);
5527}
5528
5529void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
5530 HUnresolvedInstanceFieldGet* instruction) {
5531 FieldAccessCallingConventionARM calling_convention;
5532 codegen_->GenerateUnresolvedFieldAccess(instruction,
5533 instruction->GetFieldType(),
5534 instruction->GetFieldIndex(),
5535 instruction->GetDexPc(),
5536 calling_convention);
5537}
5538
5539void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
5540 HUnresolvedInstanceFieldSet* instruction) {
5541 FieldAccessCallingConventionARM calling_convention;
5542 codegen_->CreateUnresolvedFieldLocationSummary(
5543 instruction, instruction->GetFieldType(), calling_convention);
5544}
5545
5546void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
5547 HUnresolvedInstanceFieldSet* instruction) {
5548 FieldAccessCallingConventionARM calling_convention;
5549 codegen_->GenerateUnresolvedFieldAccess(instruction,
5550 instruction->GetFieldType(),
5551 instruction->GetFieldIndex(),
5552 instruction->GetDexPc(),
5553 calling_convention);
5554}
5555
5556void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
5557 HUnresolvedStaticFieldGet* instruction) {
5558 FieldAccessCallingConventionARM calling_convention;
5559 codegen_->CreateUnresolvedFieldLocationSummary(
5560 instruction, instruction->GetFieldType(), calling_convention);
5561}
5562
5563void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
5564 HUnresolvedStaticFieldGet* instruction) {
5565 FieldAccessCallingConventionARM calling_convention;
5566 codegen_->GenerateUnresolvedFieldAccess(instruction,
5567 instruction->GetFieldType(),
5568 instruction->GetFieldIndex(),
5569 instruction->GetDexPc(),
5570 calling_convention);
5571}
5572
5573void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
5574 HUnresolvedStaticFieldSet* instruction) {
5575 FieldAccessCallingConventionARM calling_convention;
5576 codegen_->CreateUnresolvedFieldLocationSummary(
5577 instruction, instruction->GetFieldType(), calling_convention);
5578}
5579
5580void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
5581 HUnresolvedStaticFieldSet* instruction) {
5582 FieldAccessCallingConventionARM calling_convention;
5583 codegen_->GenerateUnresolvedFieldAccess(instruction,
5584 instruction->GetFieldType(),
5585 instruction->GetFieldIndex(),
5586 instruction->GetDexPc(),
5587 calling_convention);
5588}
5589
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005590void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005591 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
5592 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005593}
5594
Calin Juravle2ae48182016-03-16 14:05:09 +00005595void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
5596 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005597 return;
5598 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005599 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00005600
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005601 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00005602 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005603}
5604
Calin Juravle2ae48182016-03-16 14:05:09 +00005605void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01005606 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00005607 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005608
5609 LocationSummary* locations = instruction->GetLocations();
5610 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005611
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005612 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005613}
5614
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005615void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00005616 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005617}
5618
Artem Serov6c916792016-07-11 14:02:34 +01005619static LoadOperandType GetLoadOperandType(Primitive::Type type) {
5620 switch (type) {
5621 case Primitive::kPrimNot:
5622 return kLoadWord;
5623 case Primitive::kPrimBoolean:
5624 return kLoadUnsignedByte;
5625 case Primitive::kPrimByte:
5626 return kLoadSignedByte;
5627 case Primitive::kPrimChar:
5628 return kLoadUnsignedHalfword;
5629 case Primitive::kPrimShort:
5630 return kLoadSignedHalfword;
5631 case Primitive::kPrimInt:
5632 return kLoadWord;
5633 case Primitive::kPrimLong:
5634 return kLoadWordPair;
5635 case Primitive::kPrimFloat:
5636 return kLoadSWord;
5637 case Primitive::kPrimDouble:
5638 return kLoadDWord;
5639 default:
5640 LOG(FATAL) << "Unreachable type " << type;
5641 UNREACHABLE();
5642 }
5643}
5644
5645static StoreOperandType GetStoreOperandType(Primitive::Type type) {
5646 switch (type) {
5647 case Primitive::kPrimNot:
5648 return kStoreWord;
5649 case Primitive::kPrimBoolean:
5650 case Primitive::kPrimByte:
5651 return kStoreByte;
5652 case Primitive::kPrimChar:
5653 case Primitive::kPrimShort:
5654 return kStoreHalfword;
5655 case Primitive::kPrimInt:
5656 return kStoreWord;
5657 case Primitive::kPrimLong:
5658 return kStoreWordPair;
5659 case Primitive::kPrimFloat:
5660 return kStoreSWord;
5661 case Primitive::kPrimDouble:
5662 return kStoreDWord;
5663 default:
5664 LOG(FATAL) << "Unreachable type " << type;
5665 UNREACHABLE();
5666 }
5667}
5668
5669void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
5670 Location out_loc,
5671 Register base,
5672 Register reg_offset,
5673 Condition cond) {
5674 uint32_t shift_count = Primitive::ComponentSizeShift(type);
5675 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
5676
5677 switch (type) {
5678 case Primitive::kPrimByte:
5679 __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
5680 break;
5681 case Primitive::kPrimBoolean:
5682 __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
5683 break;
5684 case Primitive::kPrimShort:
5685 __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
5686 break;
5687 case Primitive::kPrimChar:
5688 __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
5689 break;
5690 case Primitive::kPrimNot:
5691 case Primitive::kPrimInt:
5692 __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
5693 break;
5694 // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
5695 case Primitive::kPrimLong:
5696 case Primitive::kPrimFloat:
5697 case Primitive::kPrimDouble:
5698 default:
5699 LOG(FATAL) << "Unreachable type " << type;
5700 UNREACHABLE();
5701 }
5702}
5703
5704void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
5705 Location loc,
5706 Register base,
5707 Register reg_offset,
5708 Condition cond) {
5709 uint32_t shift_count = Primitive::ComponentSizeShift(type);
5710 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
5711
5712 switch (type) {
5713 case Primitive::kPrimByte:
5714 case Primitive::kPrimBoolean:
5715 __ strb(loc.AsRegister<Register>(), mem_address, cond);
5716 break;
5717 case Primitive::kPrimShort:
5718 case Primitive::kPrimChar:
5719 __ strh(loc.AsRegister<Register>(), mem_address, cond);
5720 break;
5721 case Primitive::kPrimNot:
5722 case Primitive::kPrimInt:
5723 __ str(loc.AsRegister<Register>(), mem_address, cond);
5724 break;
5725 // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
5726 case Primitive::kPrimLong:
5727 case Primitive::kPrimFloat:
5728 case Primitive::kPrimDouble:
5729 default:
5730 LOG(FATAL) << "Unreachable type " << type;
5731 UNREACHABLE();
5732 }
5733}
5734
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005735void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005736 bool object_array_get_with_read_barrier =
5737 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005738 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00005739 new (GetGraph()->GetArena()) LocationSummary(instruction,
5740 object_array_get_with_read_barrier ?
5741 LocationSummary::kCallOnSlowPath :
5742 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005743 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005744 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005745 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005746 locations->SetInAt(0, Location::RequiresRegister());
5747 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005748 if (Primitive::IsFloatingPointType(instruction->GetType())) {
5749 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5750 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00005751 // The output overlaps in the case of an object array get with
5752 // read barriers enabled: we do not want the move to overwrite the
5753 // array's location, as we need it to emit the read barrier.
5754 locations->SetOut(
5755 Location::RequiresRegister(),
5756 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005757 }
Roland Levillainc9285912015-12-18 10:38:42 +00005758 // We need a temporary register for the read barrier marking slow
5759 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
jessicahandojo05765752016-09-09 19:01:32 -07005760 // Also need for String compression feature.
5761 if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
5762 || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
Roland Levillainc9285912015-12-18 10:38:42 +00005763 locations->AddTemp(Location::RequiresRegister());
5764 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005765}
5766
5767void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
5768 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005769 Location obj_loc = locations->InAt(0);
5770 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005771 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00005772 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01005773 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Roland Levillainc9285912015-12-18 10:38:42 +00005774 Primitive::Type type = instruction->GetType();
jessicahandojo05765752016-09-09 19:01:32 -07005775 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
5776 instruction->IsStringCharAt();
Artem Serov328429f2016-07-06 16:23:04 +01005777 HInstruction* array_instr = instruction->GetArray();
5778 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Artem Serov6c916792016-07-11 14:02:34 +01005779
Roland Levillain4d027112015-07-01 15:41:14 +01005780 switch (type) {
Artem Serov6c916792016-07-11 14:02:34 +01005781 case Primitive::kPrimBoolean:
5782 case Primitive::kPrimByte:
5783 case Primitive::kPrimShort:
5784 case Primitive::kPrimChar:
Roland Levillainc9285912015-12-18 10:38:42 +00005785 case Primitive::kPrimInt: {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005786 Register length;
5787 if (maybe_compressed_char_at) {
5788 length = locations->GetTemp(0).AsRegister<Register>();
5789 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
5790 __ LoadFromOffset(kLoadWord, length, obj, count_offset);
5791 codegen_->MaybeRecordImplicitNullCheck(instruction);
5792 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005793 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01005794 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
jessicahandojo05765752016-09-09 19:01:32 -07005795 if (maybe_compressed_char_at) {
jessicahandojo05765752016-09-09 19:01:32 -07005796 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00005797 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005798 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
5799 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
5800 "Expecting 0=compressed, 1=uncompressed");
5801 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07005802 __ LoadFromOffset(kLoadUnsignedByte,
5803 out_loc.AsRegister<Register>(),
5804 obj,
5805 data_offset + const_index);
Anton Kirilov6f644202017-02-27 18:29:45 +00005806 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07005807 __ Bind(&uncompressed_load);
5808 __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
5809 out_loc.AsRegister<Register>(),
5810 obj,
5811 data_offset + (const_index << 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00005812 if (done.IsLinked()) {
5813 __ Bind(&done);
5814 }
jessicahandojo05765752016-09-09 19:01:32 -07005815 } else {
5816 uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
Artem Serov6c916792016-07-11 14:02:34 +01005817
jessicahandojo05765752016-09-09 19:01:32 -07005818 LoadOperandType load_type = GetLoadOperandType(type);
5819 __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
5820 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005821 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005822 Register temp = IP;
5823
5824 if (has_intermediate_address) {
5825 // We do not need to compute the intermediate address from the array: the
5826 // input instruction has done it already. See the comment in
5827 // `TryExtractArrayAccessAddress()`.
5828 if (kIsDebugBuild) {
5829 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5830 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5831 }
5832 temp = obj;
5833 } else {
5834 __ add(temp, obj, ShifterOperand(data_offset));
5835 }
jessicahandojo05765752016-09-09 19:01:32 -07005836 if (maybe_compressed_char_at) {
5837 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00005838 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01005839 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
5840 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
5841 "Expecting 0=compressed, 1=uncompressed");
5842 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07005843 __ ldrb(out_loc.AsRegister<Register>(),
5844 Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
Anton Kirilov6f644202017-02-27 18:29:45 +00005845 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07005846 __ Bind(&uncompressed_load);
5847 __ ldrh(out_loc.AsRegister<Register>(),
5848 Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00005849 if (done.IsLinked()) {
5850 __ Bind(&done);
5851 }
jessicahandojo05765752016-09-09 19:01:32 -07005852 } else {
5853 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
5854 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005855 }
5856 break;
5857 }
5858
Roland Levillainc9285912015-12-18 10:38:42 +00005859 case Primitive::kPrimNot: {
Roland Levillain19c54192016-11-04 13:44:09 +00005860 // The read barrier instrumentation of object ArrayGet
5861 // instructions does not support the HIntermediateAddress
5862 // instruction.
5863 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
5864
Roland Levillainc9285912015-12-18 10:38:42 +00005865 static_assert(
5866 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
5867 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00005868 // /* HeapReference<Object> */ out =
5869 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
5870 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5871 Location temp = locations->GetTemp(0);
5872 // Note that a potential implicit null check is handled in this
5873 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
5874 codegen_->GenerateArrayLoadWithBakerReadBarrier(
5875 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
5876 } else {
5877 Register out = out_loc.AsRegister<Register>();
5878 if (index.IsConstant()) {
5879 size_t offset =
5880 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
5881 __ LoadFromOffset(kLoadWord, out, obj, offset);
5882 codegen_->MaybeRecordImplicitNullCheck(instruction);
5883 // If read barriers are enabled, emit read barriers other than
5884 // Baker's using a slow path (and also unpoison the loaded
5885 // reference, if heap poisoning is enabled).
5886 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
5887 } else {
Artem Serov328429f2016-07-06 16:23:04 +01005888 Register temp = IP;
5889
5890 if (has_intermediate_address) {
5891 // We do not need to compute the intermediate address from the array: the
5892 // input instruction has done it already. See the comment in
5893 // `TryExtractArrayAccessAddress()`.
5894 if (kIsDebugBuild) {
5895 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
5896 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
5897 }
5898 temp = obj;
5899 } else {
5900 __ add(temp, obj, ShifterOperand(data_offset));
5901 }
5902 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Artem Serov6c916792016-07-11 14:02:34 +01005903
Roland Levillainc9285912015-12-18 10:38:42 +00005904 codegen_->MaybeRecordImplicitNullCheck(instruction);
5905 // If read barriers are enabled, emit read barriers other than
5906 // Baker's using a slow path (and also unpoison the loaded
5907 // reference, if heap poisoning is enabled).
5908 codegen_->MaybeGenerateReadBarrierSlow(
5909 instruction, out_loc, out_loc, obj_loc, data_offset, index);
5910 }
5911 }
5912 break;
5913 }
5914
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005915 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005916 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005917 size_t offset =
5918 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005919 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005920 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005921 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00005922 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005923 }
5924 break;
5925 }
5926
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005927 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00005928 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005929 if (index.IsConstant()) {
5930 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005931 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005932 } else {
5933 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00005934 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005935 }
5936 break;
5937 }
5938
5939 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00005940 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005941 if (index.IsConstant()) {
5942 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00005943 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005944 } else {
5945 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00005946 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00005947 }
5948 break;
5949 }
5950
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005951 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01005952 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005953 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005954 }
Roland Levillain4d027112015-07-01 15:41:14 +01005955
5956 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00005957 // Potential implicit null checks, in the case of reference
5958 // arrays, are handled in the previous switch statement.
jessicahandojo05765752016-09-09 19:01:32 -07005959 } else if (!maybe_compressed_char_at) {
Roland Levillainc9285912015-12-18 10:38:42 +00005960 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01005961 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005962}
5963
5964void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005965 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005966
5967 bool needs_write_barrier =
5968 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00005969 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005970
Nicolas Geoffray39468442014-09-02 15:17:15 +01005971 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005972 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01005973 may_need_runtime_call_for_type_check ?
Roland Levillain3b359c72015-11-17 19:35:12 +00005974 LocationSummary::kCallOnSlowPath :
5975 LocationSummary::kNoCall);
5976
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005977 locations->SetInAt(0, Location::RequiresRegister());
5978 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
5979 if (Primitive::IsFloatingPointType(value_type)) {
5980 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005981 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005982 locations->SetInAt(2, Location::RequiresRegister());
5983 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01005984 if (needs_write_barrier) {
5985 // Temporary registers for the write barrier.
5986 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00005987 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005988 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005989}
5990
5991void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
5992 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005993 Location array_loc = locations->InAt(0);
5994 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005995 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005996 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00005997 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00005998 bool needs_write_barrier =
5999 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Artem Serov6c916792016-07-11 14:02:34 +01006000 uint32_t data_offset =
6001 mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
6002 Location value_loc = locations->InAt(2);
Artem Serov328429f2016-07-06 16:23:04 +01006003 HInstruction* array_instr = instruction->GetArray();
6004 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006005
6006 switch (value_type) {
6007 case Primitive::kPrimBoolean:
Artem Serov6c916792016-07-11 14:02:34 +01006008 case Primitive::kPrimByte:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006009 case Primitive::kPrimShort:
Artem Serov6c916792016-07-11 14:02:34 +01006010 case Primitive::kPrimChar:
6011 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006012 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01006013 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
6014 uint32_t full_offset =
6015 data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
6016 StoreOperandType store_type = GetStoreOperandType(value_type);
6017 __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006018 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006019 Register temp = IP;
6020
6021 if (has_intermediate_address) {
6022 // We do not need to compute the intermediate address from the array: the
6023 // input instruction has done it already. See the comment in
6024 // `TryExtractArrayAccessAddress()`.
6025 if (kIsDebugBuild) {
6026 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6027 DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
6028 }
6029 temp = array;
6030 } else {
6031 __ add(temp, array, ShifterOperand(data_offset));
6032 }
Artem Serov6c916792016-07-11 14:02:34 +01006033 codegen_->StoreToShiftedRegOffset(value_type,
6034 value_loc,
Artem Serov328429f2016-07-06 16:23:04 +01006035 temp,
Artem Serov6c916792016-07-11 14:02:34 +01006036 index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006037 }
6038 break;
6039 }
6040
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006041 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00006042 Register value = value_loc.AsRegister<Register>();
Artem Serov328429f2016-07-06 16:23:04 +01006043 // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
6044 // See the comment in instruction_simplifier_shared.cc.
6045 DCHECK(!has_intermediate_address);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006046
6047 if (instruction->InputAt(2)->IsNullConstant()) {
6048 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006049 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006050 size_t offset =
6051 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Artem Serov6c916792016-07-11 14:02:34 +01006052 __ StoreToOffset(kStoreWord, value, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006053 } else {
6054 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006055 __ add(IP, array, ShifterOperand(data_offset));
6056 codegen_->StoreToShiftedRegOffset(value_type,
6057 value_loc,
6058 IP,
6059 index.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006060 }
Roland Levillain1407ee72016-01-08 15:56:19 +00006061 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00006062 DCHECK(!needs_write_barrier);
6063 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006064 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006065 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006066
6067 DCHECK(needs_write_barrier);
Roland Levillain16d9f942016-08-25 17:27:56 +01006068 Location temp1_loc = locations->GetTemp(0);
6069 Register temp1 = temp1_loc.AsRegister<Register>();
6070 Location temp2_loc = locations->GetTemp(1);
6071 Register temp2 = temp2_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006072 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6073 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6074 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6075 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006076 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01006077 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006078
Roland Levillain3b359c72015-11-17 19:35:12 +00006079 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006080 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
6081 codegen_->AddSlowPath(slow_path);
6082 if (instruction->GetValueCanBeNull()) {
6083 Label non_zero;
6084 __ CompareAndBranchIfNonZero(value, &non_zero);
6085 if (index.IsConstant()) {
6086 size_t offset =
6087 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6088 __ StoreToOffset(kStoreWord, value, array, offset);
6089 } else {
6090 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006091 __ add(IP, array, ShifterOperand(data_offset));
6092 codegen_->StoreToShiftedRegOffset(value_type,
6093 value_loc,
6094 IP,
6095 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006096 }
6097 codegen_->MaybeRecordImplicitNullCheck(instruction);
Anton Kirilov6f644202017-02-27 18:29:45 +00006098 __ b(final_label);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006099 __ Bind(&non_zero);
6100 }
6101
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006102 // Note that when read barriers are enabled, the type checks
6103 // are performed without read barriers. This is fine, even in
6104 // the case where a class object is in the from-space after
6105 // the flip, as a comparison involving such a type would not
6106 // produce a false positive; it may of course produce a false
6107 // negative, in which case we would take the ArraySet slow
6108 // path.
Roland Levillain16d9f942016-08-25 17:27:56 +01006109
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006110 // /* HeapReference<Class> */ temp1 = array->klass_
6111 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
6112 codegen_->MaybeRecordImplicitNullCheck(instruction);
6113 __ MaybeUnpoisonHeapReference(temp1);
Roland Levillain16d9f942016-08-25 17:27:56 +01006114
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006115 // /* HeapReference<Class> */ temp1 = temp1->component_type_
6116 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
6117 // /* HeapReference<Class> */ temp2 = value->klass_
6118 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
6119 // If heap poisoning is enabled, no need to unpoison `temp1`
6120 // nor `temp2`, as we are comparing two poisoned references.
6121 __ cmp(temp1, ShifterOperand(temp2));
Roland Levillain16d9f942016-08-25 17:27:56 +01006122
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006123 if (instruction->StaticTypeOfArrayIsObjectArray()) {
6124 Label do_put;
6125 __ b(&do_put, EQ);
6126 // If heap poisoning is enabled, the `temp1` reference has
6127 // not been unpoisoned yet; unpoison it now.
Roland Levillain3b359c72015-11-17 19:35:12 +00006128 __ MaybeUnpoisonHeapReference(temp1);
6129
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006130 // /* HeapReference<Class> */ temp1 = temp1->super_class_
6131 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
6132 // If heap poisoning is enabled, no need to unpoison
6133 // `temp1`, as we are comparing against null below.
6134 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
6135 __ Bind(&do_put);
6136 } else {
6137 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006138 }
6139 }
6140
Artem Serov6c916792016-07-11 14:02:34 +01006141 Register source = value;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006142 if (kPoisonHeapReferences) {
6143 // Note that in the case where `value` is a null reference,
6144 // we do not enter this block, as a null reference does not
6145 // need poisoning.
6146 DCHECK_EQ(value_type, Primitive::kPrimNot);
6147 __ Mov(temp1, value);
6148 __ PoisonHeapReference(temp1);
6149 source = temp1;
6150 }
6151
6152 if (index.IsConstant()) {
6153 size_t offset =
6154 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6155 __ StoreToOffset(kStoreWord, source, array, offset);
6156 } else {
6157 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006158
6159 __ add(IP, array, ShifterOperand(data_offset));
6160 codegen_->StoreToShiftedRegOffset(value_type,
6161 Location::RegisterLocation(source),
6162 IP,
6163 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006164 }
6165
Roland Levillain3b359c72015-11-17 19:35:12 +00006166 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006167 codegen_->MaybeRecordImplicitNullCheck(instruction);
6168 }
6169
6170 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
6171
6172 if (done.IsLinked()) {
6173 __ Bind(&done);
6174 }
6175
6176 if (slow_path != nullptr) {
6177 __ Bind(slow_path->GetExitLabel());
6178 }
6179
6180 break;
6181 }
6182
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006183 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006184 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006185 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006186 size_t offset =
6187 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006188 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006189 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006190 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006191 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006192 }
6193 break;
6194 }
6195
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006196 case Primitive::kPrimFloat: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006197 Location value = locations->InAt(2);
6198 DCHECK(value.IsFpuRegister());
6199 if (index.IsConstant()) {
6200 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006201 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006202 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006203 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006204 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
6205 }
6206 break;
6207 }
6208
6209 case Primitive::kPrimDouble: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006210 Location value = locations->InAt(2);
6211 DCHECK(value.IsFpuRegisterPair());
6212 if (index.IsConstant()) {
6213 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006214 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006215 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006216 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006217 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
6218 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006219
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006220 break;
6221 }
6222
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006223 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006224 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07006225 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006226 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006227
Roland Levillain80e67092016-01-08 16:04:55 +00006228 // Objects are handled in the switch.
6229 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00006230 codegen_->MaybeRecordImplicitNullCheck(instruction);
6231 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006232}
6233
6234void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01006235 LocationSummary* locations =
6236 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006237 locations->SetInAt(0, Location::RequiresRegister());
6238 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006239}
6240
6241void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
6242 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01006243 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00006244 Register obj = locations->InAt(0).AsRegister<Register>();
6245 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006246 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00006247 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo05765752016-09-09 19:01:32 -07006248 // Mask out compression flag from String's array length.
6249 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006250 __ Lsr(out, out, 1u);
jessicahandojo05765752016-09-09 19:01:32 -07006251 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006252}
6253
Artem Serov328429f2016-07-06 16:23:04 +01006254void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
Artem Serov328429f2016-07-06 16:23:04 +01006255 LocationSummary* locations =
6256 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6257
6258 locations->SetInAt(0, Location::RequiresRegister());
6259 locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
6260 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6261}
6262
6263void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
6264 LocationSummary* locations = instruction->GetLocations();
6265 Location out = locations->Out();
6266 Location first = locations->InAt(0);
6267 Location second = locations->InAt(1);
6268
Artem Serov328429f2016-07-06 16:23:04 +01006269 if (second.IsRegister()) {
6270 __ add(out.AsRegister<Register>(),
6271 first.AsRegister<Register>(),
6272 ShifterOperand(second.AsRegister<Register>()));
6273 } else {
6274 __ AddConstant(out.AsRegister<Register>(),
6275 first.AsRegister<Register>(),
6276 second.GetConstant()->AsIntConstant()->GetValue());
6277 }
6278}
6279
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006280void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006281 RegisterSet caller_saves = RegisterSet::Empty();
6282 InvokeRuntimeCallingConvention calling_convention;
6283 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6284 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
6285 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Artem Serov2dd053d2017-03-08 14:54:06 +00006286
6287 HInstruction* index = instruction->InputAt(0);
6288 HInstruction* length = instruction->InputAt(1);
6289 // If both index and length are constants we can statically check the bounds. But if at least one
6290 // of them is not encodable ArmEncodableConstantOrRegister will create
6291 // Location::RequiresRegister() which is not desired to happen. Instead we create constant
6292 // locations.
6293 bool both_const = index->IsConstant() && length->IsConstant();
6294 locations->SetInAt(0, both_const
6295 ? Location::ConstantLocation(index->AsConstant())
6296 : ArmEncodableConstantOrRegister(index, CMP));
6297 locations->SetInAt(1, both_const
6298 ? Location::ConstantLocation(length->AsConstant())
6299 : ArmEncodableConstantOrRegister(length, CMP));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006300}
6301
6302void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
6303 LocationSummary* locations = instruction->GetLocations();
Artem Serov2dd053d2017-03-08 14:54:06 +00006304 Location index_loc = locations->InAt(0);
6305 Location length_loc = locations->InAt(1);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006306
Artem Serov2dd053d2017-03-08 14:54:06 +00006307 if (length_loc.IsConstant()) {
6308 int32_t length = helpers::Int32ConstantFrom(length_loc);
6309 if (index_loc.IsConstant()) {
6310 // BCE will remove the bounds check if we are guaranteed to pass.
6311 int32_t index = helpers::Int32ConstantFrom(index_loc);
6312 if (index < 0 || index >= length) {
6313 SlowPathCodeARM* slow_path =
6314 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6315 codegen_->AddSlowPath(slow_path);
6316 __ b(slow_path->GetEntryLabel());
6317 } else {
6318 // Some optimization after BCE may have generated this, and we should not
6319 // generate a bounds check if it is a valid range.
6320 }
6321 return;
6322 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006323
Artem Serov2dd053d2017-03-08 14:54:06 +00006324 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6325 __ cmp(index_loc.AsRegister<Register>(), ShifterOperand(length));
6326 codegen_->AddSlowPath(slow_path);
6327 __ b(slow_path->GetEntryLabel(), HS);
6328 } else {
6329 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6330 if (index_loc.IsConstant()) {
6331 int32_t index = helpers::Int32ConstantFrom(index_loc);
6332 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index));
6333 } else {
6334 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index_loc.AsRegister<Register>()));
6335 }
6336 codegen_->AddSlowPath(slow_path);
6337 __ b(slow_path->GetEntryLabel(), LS);
6338 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006339}
6340
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006341void CodeGeneratorARM::MarkGCCard(Register temp,
6342 Register card,
6343 Register object,
6344 Register value,
6345 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00006346 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006347 if (can_be_null) {
6348 __ CompareAndBranchIfZero(value, &is_null);
6349 }
Andreas Gampe542451c2016-07-26 09:02:02 -07006350 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006351 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
6352 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006353 if (can_be_null) {
6354 __ Bind(&is_null);
6355 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006356}
6357
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006358void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006359 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006360}
6361
6362void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006363 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6364}
6365
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006366void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01006367 LocationSummary* locations =
6368 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01006369 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006370}
6371
6372void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006373 HBasicBlock* block = instruction->GetBlock();
6374 if (block->GetLoopInformation() != nullptr) {
6375 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6376 // The back edge will generate the suspend check.
6377 return;
6378 }
6379 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6380 // The goto will generate the suspend check.
6381 return;
6382 }
6383 GenerateSuspendCheck(instruction, nullptr);
6384}
6385
6386void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
6387 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006388 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01006389 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
6390 if (slow_path == nullptr) {
6391 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
6392 instruction->SetSlowPath(slow_path);
6393 codegen_->AddSlowPath(slow_path);
6394 if (successor != nullptr) {
6395 DCHECK(successor->IsLoopHeader());
6396 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
6397 }
6398 } else {
6399 DCHECK_EQ(slow_path->GetSuccessor(), successor);
6400 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006401
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00006402 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07006403 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006404 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006405 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006406 __ Bind(slow_path->GetReturnLabel());
6407 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006408 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006409 __ b(slow_path->GetEntryLabel());
6410 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006411}
6412
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006413ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
6414 return codegen_->GetAssembler();
6415}
6416
6417void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006418 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006419 Location source = move->GetSource();
6420 Location destination = move->GetDestination();
6421
6422 if (source.IsRegister()) {
6423 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006424 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006425 } else if (destination.IsFpuRegister()) {
6426 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006427 } else {
6428 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006429 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006430 SP, destination.GetStackIndex());
6431 }
6432 } else if (source.IsStackSlot()) {
6433 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006434 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006435 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006436 } else if (destination.IsFpuRegister()) {
6437 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006438 } else {
6439 DCHECK(destination.IsStackSlot());
6440 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
6441 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6442 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006443 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006444 if (destination.IsRegister()) {
6445 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
6446 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006447 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006448 } else {
6449 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006450 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
6451 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006452 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006453 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006454 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
6455 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006456 } else if (destination.IsRegisterPair()) {
6457 DCHECK(ExpectedPairLayout(destination));
6458 __ LoadFromOffset(
6459 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
6460 } else {
6461 DCHECK(destination.IsFpuRegisterPair()) << destination;
6462 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6463 SP,
6464 source.GetStackIndex());
6465 }
6466 } else if (source.IsRegisterPair()) {
6467 if (destination.IsRegisterPair()) {
6468 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
6469 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006470 } else if (destination.IsFpuRegisterPair()) {
6471 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6472 source.AsRegisterPairLow<Register>(),
6473 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006474 } else {
6475 DCHECK(destination.IsDoubleStackSlot()) << destination;
6476 DCHECK(ExpectedPairLayout(source));
6477 __ StoreToOffset(
6478 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
6479 }
6480 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006481 if (destination.IsRegisterPair()) {
6482 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6483 destination.AsRegisterPairHigh<Register>(),
6484 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6485 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006486 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6487 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6488 } else {
6489 DCHECK(destination.IsDoubleStackSlot()) << destination;
6490 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
6491 SP,
6492 destination.GetStackIndex());
6493 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006494 } else {
6495 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00006496 HConstant* constant = source.GetConstant();
6497 if (constant->IsIntConstant() || constant->IsNullConstant()) {
6498 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006499 if (destination.IsRegister()) {
6500 __ LoadImmediate(destination.AsRegister<Register>(), value);
6501 } else {
6502 DCHECK(destination.IsStackSlot());
6503 __ LoadImmediate(IP, value);
6504 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6505 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006506 } else if (constant->IsLongConstant()) {
6507 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006508 if (destination.IsRegisterPair()) {
6509 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
6510 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006511 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006512 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006513 __ LoadImmediate(IP, Low32Bits(value));
6514 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6515 __ LoadImmediate(IP, High32Bits(value));
6516 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6517 }
6518 } else if (constant->IsDoubleConstant()) {
6519 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006520 if (destination.IsFpuRegisterPair()) {
6521 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006522 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006523 DCHECK(destination.IsDoubleStackSlot()) << destination;
6524 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006525 __ LoadImmediate(IP, Low32Bits(int_value));
6526 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6527 __ LoadImmediate(IP, High32Bits(int_value));
6528 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6529 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006530 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006531 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006532 float value = constant->AsFloatConstant()->GetValue();
6533 if (destination.IsFpuRegister()) {
6534 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
6535 } else {
6536 DCHECK(destination.IsStackSlot());
6537 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
6538 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6539 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006540 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006541 }
6542}
6543
6544void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
6545 __ Mov(IP, reg);
6546 __ LoadFromOffset(kLoadWord, reg, SP, mem);
6547 __ StoreToOffset(kStoreWord, IP, SP, mem);
6548}
6549
6550void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
6551 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
6552 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
6553 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
6554 SP, mem1 + stack_offset);
6555 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
6556 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
6557 SP, mem2 + stack_offset);
6558 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
6559}
6560
6561void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006562 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006563 Location source = move->GetSource();
6564 Location destination = move->GetDestination();
6565
6566 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006567 DCHECK_NE(source.AsRegister<Register>(), IP);
6568 DCHECK_NE(destination.AsRegister<Register>(), IP);
6569 __ Mov(IP, source.AsRegister<Register>());
6570 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
6571 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006572 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006573 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006574 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006575 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006576 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
6577 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006578 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006579 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006580 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006581 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006582 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006583 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006584 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006585 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006586 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6587 destination.AsRegisterPairHigh<Register>(),
6588 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006589 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006590 Register low_reg = source.IsRegisterPair()
6591 ? source.AsRegisterPairLow<Register>()
6592 : destination.AsRegisterPairLow<Register>();
6593 int mem = source.IsRegisterPair()
6594 ? destination.GetStackIndex()
6595 : source.GetStackIndex();
6596 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006597 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006598 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006599 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006600 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006601 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
6602 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006603 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006604 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006605 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006606 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
6607 DRegister reg = source.IsFpuRegisterPair()
6608 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
6609 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
6610 int mem = source.IsFpuRegisterPair()
6611 ? destination.GetStackIndex()
6612 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006613 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006614 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006615 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006616 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
6617 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
6618 : destination.AsFpuRegister<SRegister>();
6619 int mem = source.IsFpuRegister()
6620 ? destination.GetStackIndex()
6621 : source.GetStackIndex();
6622
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006623 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006624 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006625 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006626 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006627 Exchange(source.GetStackIndex(), destination.GetStackIndex());
6628 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006629 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006630 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006631 }
6632}
6633
6634void ParallelMoveResolverARM::SpillScratch(int reg) {
6635 __ Push(static_cast<Register>(reg));
6636}
6637
6638void ParallelMoveResolverARM::RestoreScratch(int reg) {
6639 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006640}
6641
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006642HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
6643 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006644 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00006645 case HLoadClass::LoadKind::kInvalid:
6646 LOG(FATAL) << "UNREACHABLE";
6647 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006648 case HLoadClass::LoadKind::kReferrersClass:
6649 break;
6650 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
6651 DCHECK(!GetCompilerOptions().GetCompilePic());
6652 break;
6653 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
6654 DCHECK(GetCompilerOptions().GetCompilePic());
6655 break;
6656 case HLoadClass::LoadKind::kBootImageAddress:
6657 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006658 case HLoadClass::LoadKind::kBssEntry:
6659 DCHECK(!Runtime::Current()->UseJitCompilation());
6660 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006661 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006662 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006663 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006664 case HLoadClass::LoadKind::kDexCacheViaMethod:
6665 break;
6666 }
6667 return desired_class_load_kind;
6668}
6669
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006670void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00006671 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
6672 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006673 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00006674 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006675 cls,
6676 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00006677 Location::RegisterLocation(R0));
Vladimir Markoea4c1262017-02-06 19:59:33 +00006678 DCHECK_EQ(calling_convention.GetRegisterAt(0), R0);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006679 return;
6680 }
Vladimir Marko41559982017-01-06 14:04:23 +00006681 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006682
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006683 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
6684 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006685 ? LocationSummary::kCallOnSlowPath
6686 : LocationSummary::kNoCall;
6687 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006688 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006689 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006690 }
6691
Vladimir Marko41559982017-01-06 14:04:23 +00006692 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006693 locations->SetInAt(0, Location::RequiresRegister());
6694 }
6695 locations->SetOut(Location::RequiresRegister());
Vladimir Markoea4c1262017-02-06 19:59:33 +00006696 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
6697 if (!kUseReadBarrier || kUseBakerReadBarrier) {
6698 // Rely on the type resolution or initialization and marking to save everything we need.
6699 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
6700 // to the custom calling convention) or by marking, so we request a different temp.
6701 locations->AddTemp(Location::RequiresRegister());
6702 RegisterSet caller_saves = RegisterSet::Empty();
6703 InvokeRuntimeCallingConvention calling_convention;
6704 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6705 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
6706 // that the the kPrimNot result register is the same as the first argument register.
6707 locations->SetCustomSlowPathCallerSaves(caller_saves);
6708 } else {
6709 // For non-Baker read barrier we have a temp-clobbering call.
6710 }
6711 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006712}
6713
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006714// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6715// move.
6716void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00006717 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
6718 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
6719 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01006720 return;
6721 }
Vladimir Marko41559982017-01-06 14:04:23 +00006722 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01006723
Vladimir Marko41559982017-01-06 14:04:23 +00006724 LocationSummary* locations = cls->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006725 Location out_loc = locations->Out();
6726 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00006727
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006728 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
6729 ? kWithoutReadBarrier
6730 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006731 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00006732 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006733 case HLoadClass::LoadKind::kReferrersClass: {
6734 DCHECK(!cls->CanCallRuntime());
6735 DCHECK(!cls->MustGenerateClinitCheck());
6736 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
6737 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartier31b12e32016-09-02 17:11:57 -07006738 GenerateGcRootFieldLoad(cls,
6739 out_loc,
6740 current_method,
6741 ArtMethod::DeclaringClassOffset().Int32Value(),
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006742 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006743 break;
6744 }
6745 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006746 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006747 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006748 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
6749 cls->GetTypeIndex()));
6750 break;
6751 }
6752 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006753 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006754 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006755 CodeGeneratorARM::PcRelativePatchInfo* labels =
6756 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
6757 __ BindTrackedLabel(&labels->movw_label);
6758 __ movw(out, /* placeholder */ 0u);
6759 __ BindTrackedLabel(&labels->movt_label);
6760 __ movt(out, /* placeholder */ 0u);
6761 __ BindTrackedLabel(&labels->add_pc_label);
6762 __ add(out, out, ShifterOperand(PC));
6763 break;
6764 }
6765 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006766 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006767 uint32_t address = dchecked_integral_cast<uint32_t>(
6768 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
6769 DCHECK_NE(address, 0u);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006770 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
6771 break;
6772 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006773 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Markoea4c1262017-02-06 19:59:33 +00006774 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
6775 ? locations->GetTemp(0).AsRegister<Register>()
6776 : out;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006777 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko1998cd02017-01-13 13:02:58 +00006778 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006779 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00006780 __ movw(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006781 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00006782 __ movt(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006783 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00006784 __ add(temp, temp, ShifterOperand(PC));
6785 GenerateGcRootFieldLoad(cls, out_loc, temp, /* offset */ 0, read_barrier_option);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006786 generate_null_check = true;
6787 break;
6788 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006789 case HLoadClass::LoadKind::kJitTableAddress: {
6790 __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
6791 cls->GetTypeIndex(),
Nicolas Geoffray5247c082017-01-13 14:17:29 +00006792 cls->GetClass()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00006793 // /* GcRoot<mirror::Class> */ out = *out
Vladimir Markoea4c1262017-02-06 19:59:33 +00006794 GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006795 break;
6796 }
Vladimir Marko41559982017-01-06 14:04:23 +00006797 case HLoadClass::LoadKind::kDexCacheViaMethod:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00006798 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00006799 LOG(FATAL) << "UNREACHABLE";
6800 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006801 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006802
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006803 if (generate_null_check || cls->MustGenerateClinitCheck()) {
6804 DCHECK(cls->CanCallRuntime());
Artem Serovf4d6aee2016-07-11 10:41:45 +01006805 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006806 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
6807 codegen_->AddSlowPath(slow_path);
6808 if (generate_null_check) {
6809 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
6810 }
6811 if (cls->MustGenerateClinitCheck()) {
6812 GenerateClassInitializationCheck(slow_path, out);
6813 } else {
6814 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006815 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006816 }
6817}
6818
6819void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
6820 LocationSummary* locations =
6821 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
6822 locations->SetInAt(0, Location::RequiresRegister());
6823 if (check->HasUses()) {
6824 locations->SetOut(Location::SameAsFirstInput());
6825 }
6826}
6827
6828void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006829 // We assume the class is not null.
Artem Serovf4d6aee2016-07-11 10:41:45 +01006830 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006831 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006832 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00006833 GenerateClassInitializationCheck(slow_path,
6834 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006835}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006836
Nicolas Geoffray424f6762014-11-03 14:51:25 +00006837void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Artem Serovf4d6aee2016-07-11 10:41:45 +01006838 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01006839 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
6840 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
6841 __ b(slow_path->GetEntryLabel(), LT);
6842 // Even if the initialized flag is set, we may be in a situation where caches are not synced
6843 // properly. Therefore, we do a memory fence.
6844 __ dmb(ISH);
6845 __ Bind(slow_path->GetExitLabel());
6846}
6847
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006848HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
6849 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006850 switch (desired_string_load_kind) {
6851 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
6852 DCHECK(!GetCompilerOptions().GetCompilePic());
6853 break;
6854 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
6855 DCHECK(GetCompilerOptions().GetCompilePic());
6856 break;
6857 case HLoadString::LoadKind::kBootImageAddress:
6858 break;
Vladimir Markoaad75c62016-10-03 08:46:48 +00006859 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01006860 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006861 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006862 case HLoadString::LoadKind::kJitTableAddress:
6863 DCHECK(Runtime::Current()->UseJitCompilation());
6864 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006865 case HLoadString::LoadKind::kDexCacheViaMethod:
6866 break;
6867 }
6868 return desired_string_load_kind;
6869}
6870
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006871void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006872 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00006873 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006874 HLoadString::LoadKind load_kind = load->GetLoadKind();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006875 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006876 locations->SetOut(Location::RegisterLocation(R0));
6877 } else {
6878 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006879 if (load_kind == HLoadString::LoadKind::kBssEntry) {
6880 if (!kUseReadBarrier || kUseBakerReadBarrier) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00006881 // Rely on the pResolveString and marking to save everything we need, including temps.
6882 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
6883 // to the custom calling convention) or by marking, so we request a different temp.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006884 locations->AddTemp(Location::RequiresRegister());
6885 RegisterSet caller_saves = RegisterSet::Empty();
6886 InvokeRuntimeCallingConvention calling_convention;
6887 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6888 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
6889 // that the the kPrimNot result register is the same as the first argument register.
6890 locations->SetCustomSlowPathCallerSaves(caller_saves);
6891 } else {
6892 // For non-Baker read barrier we have a temp-clobbering call.
6893 }
6894 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006895 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006896}
6897
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006898// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
6899// move.
6900void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01006901 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006902 Location out_loc = locations->Out();
6903 Register out = out_loc.AsRegister<Register>();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006904 HLoadString::LoadKind load_kind = load->GetLoadKind();
Roland Levillain3b359c72015-11-17 19:35:12 +00006905
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006906 switch (load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006907 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006908 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006909 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
6910 load->GetStringIndex()));
6911 return; // No dex cache slow path.
6912 }
6913 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00006914 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006915 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006916 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006917 __ BindTrackedLabel(&labels->movw_label);
6918 __ movw(out, /* placeholder */ 0u);
6919 __ BindTrackedLabel(&labels->movt_label);
6920 __ movt(out, /* placeholder */ 0u);
6921 __ BindTrackedLabel(&labels->add_pc_label);
6922 __ add(out, out, ShifterOperand(PC));
6923 return; // No dex cache slow path.
6924 }
6925 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006926 uint32_t address = dchecked_integral_cast<uint32_t>(
6927 reinterpret_cast<uintptr_t>(load->GetString().Get()));
6928 DCHECK_NE(address, 0u);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006929 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
6930 return; // No dex cache slow path.
6931 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00006932 case HLoadString::LoadKind::kBssEntry: {
6933 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markoea4c1262017-02-06 19:59:33 +00006934 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
6935 ? locations->GetTemp(0).AsRegister<Register>()
6936 : out;
Vladimir Markoaad75c62016-10-03 08:46:48 +00006937 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00006938 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markoaad75c62016-10-03 08:46:48 +00006939 __ BindTrackedLabel(&labels->movw_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006940 __ movw(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00006941 __ BindTrackedLabel(&labels->movt_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006942 __ movt(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00006943 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006944 __ add(temp, temp, ShifterOperand(PC));
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08006945 GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00006946 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
6947 codegen_->AddSlowPath(slow_path);
6948 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
6949 __ Bind(slow_path->GetExitLabel());
6950 return;
6951 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006952 case HLoadString::LoadKind::kJitTableAddress: {
6953 __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00006954 load->GetStringIndex(),
6955 load->GetString()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00006956 // /* GcRoot<mirror::String> */ out = *out
6957 GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
6958 return;
6959 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006960 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07006961 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00006962 }
Roland Levillain3b359c72015-11-17 19:35:12 +00006963
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006964 // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
6965 DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
6966 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +01006967 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08006968 __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07006969 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
6970 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00006971}
6972
David Brazdilcb1c0552015-08-04 16:22:25 +01006973static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07006974 return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
David Brazdilcb1c0552015-08-04 16:22:25 +01006975}
6976
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006977void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
6978 LocationSummary* locations =
6979 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
6980 locations->SetOut(Location::RequiresRegister());
6981}
6982
6983void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006984 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01006985 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
6986}
6987
6988void LocationsBuilderARM::VisitClearException(HClearException* clear) {
6989 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
6990}
6991
6992void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006993 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01006994 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00006995}
6996
6997void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
6998 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006999 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007000 InvokeRuntimeCallingConvention calling_convention;
7001 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7002}
7003
7004void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01007005 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007006 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007007}
7008
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007009// Temp is used for read barrier.
7010static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
7011 if (kEmitCompilerReadBarrier &&
7012 (kUseBakerReadBarrier ||
7013 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7014 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7015 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
7016 return 1;
7017 }
7018 return 0;
7019}
7020
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007021// Interface case has 3 temps, one for holding the number of interfaces, one for the current
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007022// interface pointer, one for loading the current interface.
7023// The other checks have one temp for loading the object's class.
7024static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
7025 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7026 return 3;
7027 }
7028 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Roland Levillainc9285912015-12-18 10:38:42 +00007029}
7030
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007031void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007032 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00007033 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01007034 bool baker_read_barrier_slow_path = false;
Roland Levillain3b359c72015-11-17 19:35:12 +00007035 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007036 case TypeCheckKind::kExactCheck:
7037 case TypeCheckKind::kAbstractClassCheck:
7038 case TypeCheckKind::kClassHierarchyCheck:
7039 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007040 call_kind =
7041 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01007042 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007043 break;
7044 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007045 case TypeCheckKind::kUnresolvedCheck:
7046 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007047 call_kind = LocationSummary::kCallOnSlowPath;
7048 break;
7049 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007050
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007051 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01007052 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007053 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007054 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007055 locations->SetInAt(0, Location::RequiresRegister());
7056 locations->SetInAt(1, Location::RequiresRegister());
7057 // The "out" register is used as a temporary, so it overlaps with the inputs.
7058 // Note that TypeCheckSlowPathARM uses this register too.
7059 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007060 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007061}
7062
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007063void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007064 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007065 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007066 Location obj_loc = locations->InAt(0);
7067 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007068 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007069 Location out_loc = locations->Out();
7070 Register out = out_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007071 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7072 DCHECK_LE(num_temps, 1u);
7073 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007074 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007075 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7076 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7077 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007078 Label done;
7079 Label* const final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01007080 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007081
7082 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007083 // avoid null check if we know obj is not null.
7084 if (instruction->MustDoNullCheck()) {
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007085 DCHECK_NE(out, obj);
7086 __ LoadImmediate(out, 0);
7087 __ CompareAndBranchIfZero(obj, final_label);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007088 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007089
Roland Levillainc9285912015-12-18 10:38:42 +00007090 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007091 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007092 // /* HeapReference<Class> */ out = obj->klass_
7093 GenerateReferenceLoadTwoRegisters(instruction,
7094 out_loc,
7095 obj_loc,
7096 class_offset,
7097 maybe_temp_loc,
7098 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007099 // Classes must be equal for the instanceof to succeed.
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007100 __ cmp(out, ShifterOperand(cls));
7101 // We speculatively set the result to false without changing the condition
7102 // flags, which allows us to avoid some branching later.
7103 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7104
7105 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7106 // we check that the output is in a low register, so that a 16-bit MOV
7107 // encoding can be used.
7108 if (ArmAssembler::IsLowRegister(out)) {
7109 __ it(EQ);
7110 __ mov(out, ShifterOperand(1), EQ);
7111 } else {
7112 __ b(final_label, NE);
7113 __ LoadImmediate(out, 1);
7114 }
7115
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007116 break;
7117 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007118
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007119 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007120 // /* HeapReference<Class> */ out = obj->klass_
7121 GenerateReferenceLoadTwoRegisters(instruction,
7122 out_loc,
7123 obj_loc,
7124 class_offset,
7125 maybe_temp_loc,
7126 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007127 // If the class is abstract, we eagerly fetch the super class of the
7128 // object to avoid doing a comparison we know will fail.
7129 Label loop;
7130 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007131 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007132 GenerateReferenceLoadOneRegister(instruction,
7133 out_loc,
7134 super_offset,
7135 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007136 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007137 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007138 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007139 __ cmp(out, ShifterOperand(cls));
7140 __ b(&loop, NE);
7141 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007142 break;
7143 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007144
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007145 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007146 // /* HeapReference<Class> */ out = obj->klass_
7147 GenerateReferenceLoadTwoRegisters(instruction,
7148 out_loc,
7149 obj_loc,
7150 class_offset,
7151 maybe_temp_loc,
7152 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007153 // Walk over the class hierarchy to find a match.
7154 Label loop, success;
7155 __ Bind(&loop);
7156 __ cmp(out, ShifterOperand(cls));
7157 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007158 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007159 GenerateReferenceLoadOneRegister(instruction,
7160 out_loc,
7161 super_offset,
7162 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007163 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007164 // This is essentially a null check, but it sets the condition flags to the
7165 // proper value for the code that follows the loop, i.e. not `EQ`.
7166 __ cmp(out, ShifterOperand(1));
7167 __ b(&loop, HS);
7168
7169 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7170 // we check that the output is in a low register, so that a 16-bit MOV
7171 // encoding can be used.
7172 if (ArmAssembler::IsLowRegister(out)) {
7173 // If `out` is null, we use it for the result, and the condition flags
7174 // have already been set to `NE`, so the IT block that comes afterwards
7175 // (and which handles the successful case) turns into a NOP (instead of
7176 // overwriting `out`).
7177 __ Bind(&success);
7178 // There is only one branch to the `success` label (which is bound to this
7179 // IT block), and it has the same condition, `EQ`, so in that case the MOV
7180 // is executed.
7181 __ it(EQ);
7182 __ mov(out, ShifterOperand(1), EQ);
7183 } else {
7184 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007185 __ b(final_label);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007186 __ Bind(&success);
7187 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007188 }
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007189
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007190 break;
7191 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007192
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007193 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007194 // /* HeapReference<Class> */ out = obj->klass_
7195 GenerateReferenceLoadTwoRegisters(instruction,
7196 out_loc,
7197 obj_loc,
7198 class_offset,
7199 maybe_temp_loc,
7200 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007201 // Do an exact check.
7202 Label exact_check;
7203 __ cmp(out, ShifterOperand(cls));
7204 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007205 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007206 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007207 GenerateReferenceLoadOneRegister(instruction,
7208 out_loc,
7209 component_offset,
7210 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007211 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007212 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007213 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007214 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
7215 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007216 __ cmp(out, ShifterOperand(0));
7217 // We speculatively set the result to false without changing the condition
7218 // flags, which allows us to avoid some branching later.
7219 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7220
7221 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7222 // we check that the output is in a low register, so that a 16-bit MOV
7223 // encoding can be used.
7224 if (ArmAssembler::IsLowRegister(out)) {
7225 __ Bind(&exact_check);
7226 __ it(EQ);
7227 __ mov(out, ShifterOperand(1), EQ);
7228 } else {
7229 __ b(final_label, NE);
7230 __ Bind(&exact_check);
7231 __ LoadImmediate(out, 1);
7232 }
7233
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007234 break;
7235 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007236
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007237 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007238 // No read barrier since the slow path will retry upon failure.
7239 // /* HeapReference<Class> */ out = obj->klass_
7240 GenerateReferenceLoadTwoRegisters(instruction,
7241 out_loc,
7242 obj_loc,
7243 class_offset,
7244 maybe_temp_loc,
7245 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007246 __ cmp(out, ShifterOperand(cls));
7247 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00007248 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7249 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007250 codegen_->AddSlowPath(slow_path);
7251 __ b(slow_path->GetEntryLabel(), NE);
7252 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007253 break;
7254 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007255
Calin Juravle98893e12015-10-02 21:05:03 +01007256 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007257 case TypeCheckKind::kInterfaceCheck: {
7258 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007259 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00007260 // cases.
7261 //
7262 // We cannot directly call the InstanceofNonTrivial runtime
7263 // entry point without resorting to a type checking slow path
7264 // here (i.e. by calling InvokeRuntime directly), as it would
7265 // require to assign fixed registers for the inputs of this
7266 // HInstanceOf instruction (following the runtime calling
7267 // convention), which might be cluttered by the potential first
7268 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00007269 //
7270 // TODO: Introduce a new runtime entry point taking the object
7271 // to test (instead of its class) as argument, and let it deal
7272 // with the read barrier issues. This will let us refactor this
7273 // case of the `switch` code as it was previously (with a direct
7274 // call to the runtime not using a type checking slow path).
7275 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00007276 DCHECK(locations->OnlyCallsOnSlowPath());
7277 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7278 /* is_fatal */ false);
7279 codegen_->AddSlowPath(slow_path);
7280 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007281 break;
7282 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007283 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007284
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007285 if (done.IsLinked()) {
7286 __ Bind(&done);
7287 }
7288
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007289 if (slow_path != nullptr) {
7290 __ Bind(slow_path->GetExitLabel());
7291 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007292}
7293
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007294void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007295 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7296 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
7297
Roland Levillain3b359c72015-11-17 19:35:12 +00007298 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7299 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007300 case TypeCheckKind::kExactCheck:
7301 case TypeCheckKind::kAbstractClassCheck:
7302 case TypeCheckKind::kClassHierarchyCheck:
7303 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007304 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
7305 LocationSummary::kCallOnSlowPath :
7306 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007307 break;
7308 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007309 case TypeCheckKind::kUnresolvedCheck:
7310 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007311 call_kind = LocationSummary::kCallOnSlowPath;
7312 break;
7313 }
7314
Roland Levillain3b359c72015-11-17 19:35:12 +00007315 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
7316 locations->SetInAt(0, Location::RequiresRegister());
7317 locations->SetInAt(1, Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007318 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007319}
7320
7321void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007322 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007323 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007324 Location obj_loc = locations->InAt(0);
7325 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007326 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007327 Location temp_loc = locations->GetTemp(0);
7328 Register temp = temp_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007329 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
7330 DCHECK_LE(num_temps, 3u);
7331 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
7332 Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
7333 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7334 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7335 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7336 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7337 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
7338 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
7339 const uint32_t object_array_data_offset =
7340 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007341
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007342 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
7343 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
7344 // read barriers is done for performance and code size reasons.
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007345 bool is_type_check_slow_path_fatal = false;
7346 if (!kEmitCompilerReadBarrier) {
7347 is_type_check_slow_path_fatal =
7348 (type_check_kind == TypeCheckKind::kExactCheck ||
7349 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7350 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7351 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
7352 !instruction->CanThrowIntoCatchBlock();
7353 }
Artem Serovf4d6aee2016-07-11 10:41:45 +01007354 SlowPathCodeARM* type_check_slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00007355 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7356 is_type_check_slow_path_fatal);
7357 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007358
7359 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00007360 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007361 // Avoid null check if we know obj is not null.
7362 if (instruction->MustDoNullCheck()) {
Anton Kirilov6f644202017-02-27 18:29:45 +00007363 __ CompareAndBranchIfZero(obj, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007364 }
7365
Roland Levillain3b359c72015-11-17 19:35:12 +00007366 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007367 case TypeCheckKind::kExactCheck:
7368 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007369 // /* HeapReference<Class> */ temp = obj->klass_
7370 GenerateReferenceLoadTwoRegisters(instruction,
7371 temp_loc,
7372 obj_loc,
7373 class_offset,
7374 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007375 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007376
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007377 __ cmp(temp, ShifterOperand(cls));
7378 // Jump to slow path for throwing the exception or doing a
7379 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00007380 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007381 break;
7382 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007383
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007384 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007385 // /* HeapReference<Class> */ temp = obj->klass_
7386 GenerateReferenceLoadTwoRegisters(instruction,
7387 temp_loc,
7388 obj_loc,
7389 class_offset,
7390 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007391 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007392
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007393 // If the class is abstract, we eagerly fetch the super class of the
7394 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007395 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007396 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007397 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007398 GenerateReferenceLoadOneRegister(instruction,
7399 temp_loc,
7400 super_offset,
7401 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007402 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007403
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007404 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7405 // exception.
7406 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
Roland Levillain3b359c72015-11-17 19:35:12 +00007407
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007408 // Otherwise, compare the classes.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007409 __ cmp(temp, ShifterOperand(cls));
7410 __ b(&loop, NE);
7411 break;
7412 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007413
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007414 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007415 // /* HeapReference<Class> */ temp = obj->klass_
7416 GenerateReferenceLoadTwoRegisters(instruction,
7417 temp_loc,
7418 obj_loc,
7419 class_offset,
7420 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007421 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007422
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007423 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007424 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007425 __ Bind(&loop);
7426 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007427 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007428
Roland Levillain3b359c72015-11-17 19:35:12 +00007429 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007430 GenerateReferenceLoadOneRegister(instruction,
7431 temp_loc,
7432 super_offset,
7433 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007434 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007435
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007436 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7437 // exception.
7438 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7439 // Otherwise, jump to the beginning of the loop.
7440 __ b(&loop);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007441 break;
7442 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007443
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007444 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007445 // /* HeapReference<Class> */ temp = obj->klass_
7446 GenerateReferenceLoadTwoRegisters(instruction,
7447 temp_loc,
7448 obj_loc,
7449 class_offset,
7450 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007451 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007452
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007453 // Do an exact check.
7454 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007455 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007456
7457 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007458 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007459 GenerateReferenceLoadOneRegister(instruction,
7460 temp_loc,
7461 component_offset,
7462 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007463 kWithoutReadBarrier);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007464 // If the component type is null, jump to the slow path to throw the exception.
7465 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7466 // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
7467 // to further check that this component type is not a primitive type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007468 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00007469 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007470 __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007471 break;
7472 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007473
Calin Juravle98893e12015-10-02 21:05:03 +01007474 case TypeCheckKind::kUnresolvedCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007475 // We always go into the type check slow path for the unresolved check case.
Roland Levillain3b359c72015-11-17 19:35:12 +00007476 // We cannot directly call the CheckCast runtime entry point
7477 // without resorting to a type checking slow path here (i.e. by
7478 // calling InvokeRuntime directly), as it would require to
7479 // assign fixed registers for the inputs of this HInstanceOf
7480 // instruction (following the runtime calling convention), which
7481 // might be cluttered by the potential first read barrier
7482 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007483
Roland Levillain3b359c72015-11-17 19:35:12 +00007484 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007485 break;
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007486
7487 case TypeCheckKind::kInterfaceCheck: {
7488 // Avoid read barriers to improve performance of the fast path. We can not get false
7489 // positives by doing this.
7490 // /* HeapReference<Class> */ temp = obj->klass_
7491 GenerateReferenceLoadTwoRegisters(instruction,
7492 temp_loc,
7493 obj_loc,
7494 class_offset,
7495 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007496 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007497
7498 // /* HeapReference<Class> */ temp = temp->iftable_
7499 GenerateReferenceLoadTwoRegisters(instruction,
7500 temp_loc,
7501 temp_loc,
7502 iftable_offset,
7503 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007504 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08007505 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007506 __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08007507 // Loop through the iftable and check if any class matches.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007508 Label start_loop;
7509 __ Bind(&start_loop);
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007510 __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
7511 type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007512 __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
7513 __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007514 // Go to next interface.
7515 __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
7516 __ sub(maybe_temp2_loc.AsRegister<Register>(),
7517 maybe_temp2_loc.AsRegister<Register>(),
7518 ShifterOperand(2));
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007519 // Compare the classes and continue the loop if they do not match.
7520 __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
7521 __ b(&start_loop, NE);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007522 break;
7523 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007524 }
Anton Kirilov6f644202017-02-27 18:29:45 +00007525
7526 if (done.IsLinked()) {
7527 __ Bind(&done);
7528 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007529
Roland Levillain3b359c72015-11-17 19:35:12 +00007530 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007531}
7532
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007533void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
7534 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01007535 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007536 InvokeRuntimeCallingConvention calling_convention;
7537 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7538}
7539
7540void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01007541 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
7542 instruction,
7543 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007544 if (instruction->IsEnter()) {
7545 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
7546 } else {
7547 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
7548 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007549}
7550
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007551void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
7552void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
7553void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007554
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007555void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007556 LocationSummary* locations =
7557 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7558 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7559 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007560 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007561 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007562 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00007563 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007564}
7565
7566void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
7567 HandleBitwiseOperation(instruction);
7568}
7569
7570void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
7571 HandleBitwiseOperation(instruction);
7572}
7573
7574void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
7575 HandleBitwiseOperation(instruction);
7576}
7577
Artem Serov7fc63502016-02-09 17:15:29 +00007578
7579void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7580 LocationSummary* locations =
7581 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7582 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7583 || instruction->GetResultType() == Primitive::kPrimLong);
7584
7585 locations->SetInAt(0, Location::RequiresRegister());
7586 locations->SetInAt(1, Location::RequiresRegister());
7587 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7588}
7589
7590void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7591 LocationSummary* locations = instruction->GetLocations();
7592 Location first = locations->InAt(0);
7593 Location second = locations->InAt(1);
7594 Location out = locations->Out();
7595
7596 if (instruction->GetResultType() == Primitive::kPrimInt) {
7597 Register first_reg = first.AsRegister<Register>();
7598 ShifterOperand second_reg(second.AsRegister<Register>());
7599 Register out_reg = out.AsRegister<Register>();
7600
7601 switch (instruction->GetOpKind()) {
7602 case HInstruction::kAnd:
7603 __ bic(out_reg, first_reg, second_reg);
7604 break;
7605 case HInstruction::kOr:
7606 __ orn(out_reg, first_reg, second_reg);
7607 break;
7608 // There is no EON on arm.
7609 case HInstruction::kXor:
7610 default:
7611 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7612 UNREACHABLE();
7613 }
7614 return;
7615
7616 } else {
7617 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7618 Register first_low = first.AsRegisterPairLow<Register>();
7619 Register first_high = first.AsRegisterPairHigh<Register>();
7620 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
7621 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
7622 Register out_low = out.AsRegisterPairLow<Register>();
7623 Register out_high = out.AsRegisterPairHigh<Register>();
7624
7625 switch (instruction->GetOpKind()) {
7626 case HInstruction::kAnd:
7627 __ bic(out_low, first_low, second_low);
7628 __ bic(out_high, first_high, second_high);
7629 break;
7630 case HInstruction::kOr:
7631 __ orn(out_low, first_low, second_low);
7632 __ orn(out_high, first_high, second_high);
7633 break;
7634 // There is no EON on arm.
7635 case HInstruction::kXor:
7636 default:
7637 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7638 UNREACHABLE();
7639 }
7640 }
7641}
7642
Anton Kirilov74234da2017-01-13 14:42:47 +00007643void LocationsBuilderARM::VisitDataProcWithShifterOp(
7644 HDataProcWithShifterOp* instruction) {
7645 DCHECK(instruction->GetType() == Primitive::kPrimInt ||
7646 instruction->GetType() == Primitive::kPrimLong);
7647 LocationSummary* locations =
7648 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7649 const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
7650 HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
7651
7652 locations->SetInAt(0, Location::RequiresRegister());
7653 locations->SetInAt(1, Location::RequiresRegister());
7654 locations->SetOut(Location::RequiresRegister(),
7655 overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
7656}
7657
7658void InstructionCodeGeneratorARM::VisitDataProcWithShifterOp(
7659 HDataProcWithShifterOp* instruction) {
7660 const LocationSummary* const locations = instruction->GetLocations();
7661 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
7662 const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
7663 const Location left = locations->InAt(0);
7664 const Location right = locations->InAt(1);
7665 const Location out = locations->Out();
7666
7667 if (instruction->GetType() == Primitive::kPrimInt) {
7668 DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
7669
7670 const Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
7671 ? right.AsRegisterPairLow<Register>()
7672 : right.AsRegister<Register>();
7673
7674 GenerateDataProcInstruction(kind,
7675 out.AsRegister<Register>(),
7676 left.AsRegister<Register>(),
7677 ShifterOperand(second,
7678 ShiftFromOpKind(op_kind),
7679 instruction->GetShiftAmount()),
7680 codegen_);
7681 } else {
7682 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
7683
7684 if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
7685 const Register second = right.AsRegister<Register>();
7686
7687 DCHECK_NE(out.AsRegisterPairLow<Register>(), second);
7688 GenerateDataProc(kind,
7689 out,
7690 left,
7691 ShifterOperand(second),
7692 ShifterOperand(second, ASR, 31),
7693 codegen_);
7694 } else {
7695 GenerateLongDataProc(instruction, codegen_);
7696 }
7697 }
7698}
7699
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007700void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
7701 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
7702 if (value == 0xffffffffu) {
7703 if (out != first) {
7704 __ mov(out, ShifterOperand(first));
7705 }
7706 return;
7707 }
7708 if (value == 0u) {
7709 __ mov(out, ShifterOperand(0));
7710 return;
7711 }
7712 ShifterOperand so;
7713 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
7714 __ and_(out, first, so);
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00007715 } else if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007716 __ bic(out, first, ShifterOperand(~value));
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00007717 } else {
7718 DCHECK(IsPowerOfTwo(value + 1));
7719 __ ubfx(out, first, 0, WhichPowerOf2(value + 1));
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007720 }
7721}
7722
7723void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
7724 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
7725 if (value == 0u) {
7726 if (out != first) {
7727 __ mov(out, ShifterOperand(first));
7728 }
7729 return;
7730 }
7731 if (value == 0xffffffffu) {
7732 __ mvn(out, ShifterOperand(0));
7733 return;
7734 }
7735 ShifterOperand so;
7736 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
7737 __ orr(out, first, so);
7738 } else {
7739 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
7740 __ orn(out, first, ShifterOperand(~value));
7741 }
7742}
7743
7744void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
7745 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
7746 if (value == 0u) {
7747 if (out != first) {
7748 __ mov(out, ShifterOperand(first));
7749 }
7750 return;
7751 }
7752 __ eor(out, first, ShifterOperand(value));
7753}
7754
Vladimir Marko59751a72016-08-05 14:37:27 +01007755void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
7756 Location first,
7757 uint64_t value) {
7758 Register out_low = out.AsRegisterPairLow<Register>();
7759 Register out_high = out.AsRegisterPairHigh<Register>();
7760 Register first_low = first.AsRegisterPairLow<Register>();
7761 Register first_high = first.AsRegisterPairHigh<Register>();
7762 uint32_t value_low = Low32Bits(value);
7763 uint32_t value_high = High32Bits(value);
7764 if (value_low == 0u) {
7765 if (out_low != first_low) {
7766 __ mov(out_low, ShifterOperand(first_low));
7767 }
7768 __ AddConstant(out_high, first_high, value_high);
7769 return;
7770 }
7771 __ AddConstantSetFlags(out_low, first_low, value_low);
7772 ShifterOperand so;
7773 if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
7774 __ adc(out_high, first_high, so);
7775 } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
7776 __ sbc(out_high, first_high, so);
7777 } else {
7778 LOG(FATAL) << "Unexpected constant " << value_high;
7779 UNREACHABLE();
7780 }
7781}
7782
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007783void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
7784 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007785 Location first = locations->InAt(0);
7786 Location second = locations->InAt(1);
7787 Location out = locations->Out();
7788
7789 if (second.IsConstant()) {
7790 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
7791 uint32_t value_low = Low32Bits(value);
7792 if (instruction->GetResultType() == Primitive::kPrimInt) {
7793 Register first_reg = first.AsRegister<Register>();
7794 Register out_reg = out.AsRegister<Register>();
7795 if (instruction->IsAnd()) {
7796 GenerateAndConst(out_reg, first_reg, value_low);
7797 } else if (instruction->IsOr()) {
7798 GenerateOrrConst(out_reg, first_reg, value_low);
7799 } else {
7800 DCHECK(instruction->IsXor());
7801 GenerateEorConst(out_reg, first_reg, value_low);
7802 }
7803 } else {
7804 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7805 uint32_t value_high = High32Bits(value);
7806 Register first_low = first.AsRegisterPairLow<Register>();
7807 Register first_high = first.AsRegisterPairHigh<Register>();
7808 Register out_low = out.AsRegisterPairLow<Register>();
7809 Register out_high = out.AsRegisterPairHigh<Register>();
7810 if (instruction->IsAnd()) {
7811 GenerateAndConst(out_low, first_low, value_low);
7812 GenerateAndConst(out_high, first_high, value_high);
7813 } else if (instruction->IsOr()) {
7814 GenerateOrrConst(out_low, first_low, value_low);
7815 GenerateOrrConst(out_high, first_high, value_high);
7816 } else {
7817 DCHECK(instruction->IsXor());
7818 GenerateEorConst(out_low, first_low, value_low);
7819 GenerateEorConst(out_high, first_high, value_high);
7820 }
7821 }
7822 return;
7823 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007824
7825 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007826 Register first_reg = first.AsRegister<Register>();
7827 ShifterOperand second_reg(second.AsRegister<Register>());
7828 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007829 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007830 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007831 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007832 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007833 } else {
7834 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007835 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007836 }
7837 } else {
7838 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007839 Register first_low = first.AsRegisterPairLow<Register>();
7840 Register first_high = first.AsRegisterPairHigh<Register>();
7841 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
7842 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
7843 Register out_low = out.AsRegisterPairLow<Register>();
7844 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007845 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007846 __ and_(out_low, first_low, second_low);
7847 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007848 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007849 __ orr(out_low, first_low, second_low);
7850 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007851 } else {
7852 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007853 __ eor(out_low, first_low, second_low);
7854 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007855 }
7856 }
7857}
7858
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007859void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
7860 HInstruction* instruction,
7861 Location out,
7862 uint32_t offset,
7863 Location maybe_temp,
7864 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00007865 Register out_reg = out.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007866 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007867 CHECK(kEmitCompilerReadBarrier);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007868 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00007869 if (kUseBakerReadBarrier) {
7870 // Load with fast path based Baker's read barrier.
7871 // /* HeapReference<Object> */ out = *(out + offset)
7872 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007873 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00007874 } else {
7875 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007876 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00007877 // in the following move operation, as we will need it for the
7878 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007879 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00007880 // /* HeapReference<Object> */ out = *(out + offset)
7881 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007882 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00007883 }
7884 } else {
7885 // Plain load with no read barrier.
7886 // /* HeapReference<Object> */ out = *(out + offset)
7887 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
7888 __ MaybeUnpoisonHeapReference(out_reg);
7889 }
7890}
7891
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007892void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
7893 HInstruction* instruction,
7894 Location out,
7895 Location obj,
7896 uint32_t offset,
7897 Location maybe_temp,
7898 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00007899 Register out_reg = out.AsRegister<Register>();
7900 Register obj_reg = obj.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007901 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007902 CHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00007903 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007904 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00007905 // Load with fast path based Baker's read barrier.
7906 // /* HeapReference<Object> */ out = *(obj + offset)
7907 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00007908 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00007909 } else {
7910 // Load with slow path based read barrier.
7911 // /* HeapReference<Object> */ out = *(obj + offset)
7912 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
7913 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
7914 }
7915 } else {
7916 // Plain load with no read barrier.
7917 // /* HeapReference<Object> */ out = *(obj + offset)
7918 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
7919 __ MaybeUnpoisonHeapReference(out_reg);
7920 }
7921}
7922
7923void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
7924 Location root,
7925 Register obj,
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007926 uint32_t offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007927 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00007928 Register root_reg = root.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007929 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007930 DCHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00007931 if (kUseBakerReadBarrier) {
7932 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
Roland Levillainba650a42017-03-06 13:52:32 +00007933 // Baker's read barrier are used.
Roland Levillainc9285912015-12-18 10:38:42 +00007934 //
Roland Levillainba650a42017-03-06 13:52:32 +00007935 // Note that we do not actually check the value of
7936 // `GetIsGcMarking()` to decide whether to mark the loaded GC
7937 // root or not. Instead, we load into `temp` the read barrier
7938 // mark entry point corresponding to register `root`. If `temp`
7939 // is null, it means that `GetIsGcMarking()` is false, and vice
7940 // versa.
7941 //
Mathieu Chartierfe814e82016-11-09 14:32:49 -08007942 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
Roland Levillainba650a42017-03-06 13:52:32 +00007943 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
7944 // if (temp != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
7945 // // Slow path.
7946 // root = temp(root); // root = ReadBarrier::Mark(root); // Runtime entry point call.
Roland Levillainc9285912015-12-18 10:38:42 +00007947 // }
7948
Roland Levillainba650a42017-03-06 13:52:32 +00007949 // Slow path marking the GC root `root`. The entrypoint will already be loaded in `temp`.
7950 Location temp = Location::RegisterLocation(LR);
7951 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
7952 instruction, root, /* entrypoint */ temp);
7953 codegen_->AddSlowPath(slow_path);
7954
7955 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
7956 const int32_t entry_point_offset =
7957 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
7958 // Loading the entrypoint does not require a load acquire since it is only changed when
7959 // threads are suspended or running a checkpoint.
7960 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
7961
Roland Levillainc9285912015-12-18 10:38:42 +00007962 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7963 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
7964 static_assert(
7965 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
7966 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
7967 "have different sizes.");
7968 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
7969 "art::mirror::CompressedReference<mirror::Object> and int32_t "
7970 "have different sizes.");
7971
Mathieu Chartierfe814e82016-11-09 14:32:49 -08007972 // The entrypoint is null when the GC is not marking, this prevents one load compared to
7973 // checking GetIsGcMarking.
7974 __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillainc9285912015-12-18 10:38:42 +00007975 __ Bind(slow_path->GetExitLabel());
7976 } else {
7977 // GC root loaded through a slow path for read barriers other
7978 // than Baker's.
7979 // /* GcRoot<mirror::Object>* */ root = obj + offset
7980 __ AddConstant(root_reg, obj, offset);
7981 // /* mirror::Object* */ root = root->Read()
7982 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
7983 }
7984 } else {
7985 // Plain GC root load with no read barrier.
7986 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7987 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
7988 // Note that GC roots are not affected by heap poisoning, thus we
7989 // do not have to unpoison `root_reg` here.
7990 }
7991}
7992
7993void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
7994 Location ref,
7995 Register obj,
7996 uint32_t offset,
7997 Location temp,
7998 bool needs_null_check) {
7999 DCHECK(kEmitCompilerReadBarrier);
8000 DCHECK(kUseBakerReadBarrier);
8001
8002 // /* HeapReference<Object> */ ref = *(obj + offset)
8003 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01008004 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00008005 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008006 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008007}
8008
8009void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
8010 Location ref,
8011 Register obj,
8012 uint32_t data_offset,
8013 Location index,
8014 Location temp,
8015 bool needs_null_check) {
8016 DCHECK(kEmitCompilerReadBarrier);
8017 DCHECK(kUseBakerReadBarrier);
8018
Roland Levillainbfea3352016-06-23 13:48:47 +01008019 static_assert(
8020 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
8021 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00008022 // /* HeapReference<Object> */ ref =
8023 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Roland Levillainbfea3352016-06-23 13:48:47 +01008024 ScaleFactor scale_factor = TIMES_4;
Roland Levillainc9285912015-12-18 10:38:42 +00008025 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008026 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008027}
8028
8029void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
8030 Location ref,
8031 Register obj,
8032 uint32_t offset,
8033 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01008034 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00008035 Location temp,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008036 bool needs_null_check,
8037 bool always_update_field,
8038 Register* temp2) {
Roland Levillainc9285912015-12-18 10:38:42 +00008039 DCHECK(kEmitCompilerReadBarrier);
8040 DCHECK(kUseBakerReadBarrier);
8041
Roland Levillain54f869e2017-03-06 13:54:11 +00008042 // Query `art::Thread::Current()->GetIsGcMarking()` to decide
8043 // whether we need to enter the slow path to mark the reference.
8044 // Then, in the slow path, check the gray bit in the lock word of
8045 // the reference's holder (`obj`) to decide whether to mark `ref` or
8046 // not.
Roland Levillainc9285912015-12-18 10:38:42 +00008047 //
Roland Levillainba650a42017-03-06 13:52:32 +00008048 // Note that we do not actually check the value of `GetIsGcMarking()`;
8049 // instead, we load into `temp3` the read barrier mark entry point
8050 // corresponding to register `ref`. If `temp3` is null, it means
8051 // that `GetIsGcMarking()` is false, and vice versa.
8052 //
8053 // temp3 = Thread::Current()->pReadBarrierMarkReg ## root.reg()
Roland Levillainba650a42017-03-06 13:52:32 +00008054 // if (temp3 != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8055 // // Slow path.
Roland Levillain54f869e2017-03-06 13:54:11 +00008056 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8057 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
8058 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8059 // bool is_gray = (rb_state == ReadBarrier::GrayState());
8060 // if (is_gray) {
8061 // ref = temp3(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
8062 // }
8063 // } else {
8064 // HeapReference<mirror::Object> ref = *src; // Original reference load.
Roland Levillainc9285912015-12-18 10:38:42 +00008065 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008066
Roland Levillain35345a52017-02-27 14:32:08 +00008067 Register temp_reg = temp.AsRegister<Register>();
Roland Levillain1372c9f2017-01-13 11:47:39 +00008068
Roland Levillainba650a42017-03-06 13:52:32 +00008069 // Slow path marking the object `ref` when the GC is marking. The
8070 // entrypoint will already be loaded in `temp3`.
8071 Location temp3 = Location::RegisterLocation(LR);
8072 SlowPathCodeARM* slow_path;
8073 if (always_update_field) {
8074 DCHECK(temp2 != nullptr);
Roland Levillain54f869e2017-03-06 13:54:11 +00008075 // LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM only
8076 // supports address of the form `obj + field_offset`, where `obj`
8077 // is a register and `field_offset` is a register pair (of which
8078 // only the lower half is used). Thus `offset` and `scale_factor`
8079 // above are expected to be null in this code path.
Roland Levillainba650a42017-03-06 13:52:32 +00008080 DCHECK_EQ(offset, 0u);
8081 DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
Roland Levillain54f869e2017-03-06 13:54:11 +00008082 Location field_offset = index;
8083 slow_path =
8084 new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(
8085 instruction,
8086 ref,
8087 obj,
8088 offset,
8089 /* index */ field_offset,
8090 scale_factor,
8091 needs_null_check,
8092 temp_reg,
8093 *temp2,
8094 /* entrypoint */ temp3);
Roland Levillainba650a42017-03-06 13:52:32 +00008095 } else {
Roland Levillain54f869e2017-03-06 13:54:11 +00008096 slow_path = new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierSlowPathARM(
8097 instruction,
8098 ref,
8099 obj,
8100 offset,
8101 index,
8102 scale_factor,
8103 needs_null_check,
8104 temp_reg,
8105 /* entrypoint */ temp3);
Roland Levillain35345a52017-02-27 14:32:08 +00008106 }
Roland Levillainba650a42017-03-06 13:52:32 +00008107 AddSlowPath(slow_path);
Roland Levillain35345a52017-02-27 14:32:08 +00008108
Roland Levillainba650a42017-03-06 13:52:32 +00008109 // temp3 = Thread::Current()->pReadBarrierMarkReg ## ref.reg()
8110 const int32_t entry_point_offset =
8111 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref.reg());
8112 // Loading the entrypoint does not require a load acquire since it is only changed when
8113 // threads are suspended or running a checkpoint.
8114 __ LoadFromOffset(kLoadWord, temp3.AsRegister<Register>(), TR, entry_point_offset);
Roland Levillainba650a42017-03-06 13:52:32 +00008115 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8116 // checking GetIsGcMarking.
8117 __ CompareAndBranchIfNonZero(temp3.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillain54f869e2017-03-06 13:54:11 +00008118 // Fast path: just load the reference.
8119 GenerateRawReferenceLoad(instruction, ref, obj, offset, index, scale_factor, needs_null_check);
Roland Levillainba650a42017-03-06 13:52:32 +00008120 __ Bind(slow_path->GetExitLabel());
8121}
Roland Levillain35345a52017-02-27 14:32:08 +00008122
Roland Levillainba650a42017-03-06 13:52:32 +00008123void CodeGeneratorARM::GenerateRawReferenceLoad(HInstruction* instruction,
8124 Location ref,
8125 Register obj,
8126 uint32_t offset,
8127 Location index,
8128 ScaleFactor scale_factor,
8129 bool needs_null_check) {
8130 Register ref_reg = ref.AsRegister<Register>();
8131
Roland Levillainc9285912015-12-18 10:38:42 +00008132 if (index.IsValid()) {
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008133 // Load types involving an "index": ArrayGet,
8134 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8135 // intrinsics.
Roland Levillainba650a42017-03-06 13:52:32 +00008136 // /* HeapReference<mirror::Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00008137 if (index.IsConstant()) {
8138 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01008139 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00008140 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
8141 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01008142 // Handle the special case of the
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008143 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8144 // intrinsics, which use a register pair as index ("long
8145 // offset"), of which only the low part contains data.
Roland Levillainbfea3352016-06-23 13:48:47 +01008146 Register index_reg = index.IsRegisterPair()
8147 ? index.AsRegisterPairLow<Register>()
8148 : index.AsRegister<Register>();
8149 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00008150 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
8151 }
8152 } else {
Roland Levillainba650a42017-03-06 13:52:32 +00008153 // /* HeapReference<mirror::Object> */ ref = *(obj + offset)
Roland Levillainc9285912015-12-18 10:38:42 +00008154 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
8155 }
8156
Roland Levillainba650a42017-03-06 13:52:32 +00008157 if (needs_null_check) {
8158 MaybeRecordImplicitNullCheck(instruction);
8159 }
8160
Roland Levillainc9285912015-12-18 10:38:42 +00008161 // Object* ref = ref_addr->AsMirrorPtr()
8162 __ MaybeUnpoisonHeapReference(ref_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00008163}
8164
8165void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
8166 Location out,
8167 Location ref,
8168 Location obj,
8169 uint32_t offset,
8170 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008171 DCHECK(kEmitCompilerReadBarrier);
8172
Roland Levillainc9285912015-12-18 10:38:42 +00008173 // Insert a slow path based read barrier *after* the reference load.
8174 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008175 // If heap poisoning is enabled, the unpoisoning of the loaded
8176 // reference will be carried out by the runtime within the slow
8177 // path.
8178 //
8179 // Note that `ref` currently does not get unpoisoned (when heap
8180 // poisoning is enabled), which is alright as the `ref` argument is
8181 // not used by the artReadBarrierSlow entry point.
8182 //
8183 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008184 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
Roland Levillain3b359c72015-11-17 19:35:12 +00008185 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
8186 AddSlowPath(slow_path);
8187
Roland Levillain3b359c72015-11-17 19:35:12 +00008188 __ b(slow_path->GetEntryLabel());
8189 __ Bind(slow_path->GetExitLabel());
8190}
8191
Roland Levillainc9285912015-12-18 10:38:42 +00008192void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
8193 Location out,
8194 Location ref,
8195 Location obj,
8196 uint32_t offset,
8197 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008198 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00008199 // Baker's read barriers shall be handled by the fast path
8200 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
8201 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00008202 // If heap poisoning is enabled, unpoisoning will be taken care of
8203 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00008204 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00008205 } else if (kPoisonHeapReferences) {
8206 __ UnpoisonHeapReference(out.AsRegister<Register>());
8207 }
8208}
8209
Roland Levillainc9285912015-12-18 10:38:42 +00008210void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
8211 Location out,
8212 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008213 DCHECK(kEmitCompilerReadBarrier);
8214
Roland Levillainc9285912015-12-18 10:38:42 +00008215 // Insert a slow path based read barrier *after* the GC root load.
8216 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008217 // Note that GC roots are not affected by heap poisoning, so we do
8218 // not need to do anything special for this here.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008219 SlowPathCodeARM* slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00008220 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
8221 AddSlowPath(slow_path);
8222
Roland Levillain3b359c72015-11-17 19:35:12 +00008223 __ b(slow_path->GetEntryLabel());
8224 __ Bind(slow_path->GetExitLabel());
8225}
8226
Vladimir Markodc151b22015-10-15 18:02:30 +01008227HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
8228 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +00008229 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffraye807ff72017-01-23 09:03:12 +00008230 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01008231}
8232
Vladimir Markob4536b72015-11-24 13:45:23 +00008233Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
8234 Register temp) {
8235 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
8236 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
8237 if (!invoke->GetLocations()->Intrinsified()) {
8238 return location.AsRegister<Register>();
8239 }
8240 // For intrinsics we allow any location, so it may be on the stack.
8241 if (!location.IsRegister()) {
8242 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
8243 return temp;
8244 }
8245 // For register locations, check if the register was saved. If so, get it from the stack.
8246 // Note: There is a chance that the register was saved but not overwritten, so we could
8247 // save one load. However, since this is just an intrinsic slow path we prefer this
8248 // simple and more robust approach rather that trying to determine if that's the case.
8249 SlowPathCode* slow_path = GetCurrentSlowPath();
TatWai Chongd8c052a2016-11-02 16:12:48 +08008250 if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
Vladimir Markob4536b72015-11-24 13:45:23 +00008251 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
8252 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
8253 return temp;
8254 }
8255 return location.AsRegister<Register>();
8256}
8257
TatWai Chongd8c052a2016-11-02 16:12:48 +08008258Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
8259 Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00008260 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
8261 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008262 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
8263 uint32_t offset =
8264 GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Vladimir Marko58155012015-08-19 12:49:41 +00008265 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008266 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
Vladimir Marko58155012015-08-19 12:49:41 +00008267 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008268 }
Vladimir Marko58155012015-08-19 12:49:41 +00008269 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00008270 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00008271 break;
8272 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
8273 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
8274 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00008275 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
8276 HArmDexCacheArraysBase* base =
8277 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
8278 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
8279 temp.AsRegister<Register>());
8280 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
8281 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
8282 break;
8283 }
Vladimir Marko58155012015-08-19 12:49:41 +00008284 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00008285 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00008286 Register method_reg;
8287 Register reg = temp.AsRegister<Register>();
8288 if (current_method.IsRegister()) {
8289 method_reg = current_method.AsRegister<Register>();
8290 } else {
8291 DCHECK(invoke->GetLocations()->Intrinsified());
8292 DCHECK(!current_method.IsValid());
8293 method_reg = reg;
8294 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
8295 }
Roland Levillain3b359c72015-11-17 19:35:12 +00008296 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
8297 __ LoadFromOffset(kLoadWord,
8298 reg,
8299 method_reg,
8300 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01008301 // temp = temp[index_in_cache];
8302 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
8303 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00008304 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
8305 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01008306 }
Vladimir Marko58155012015-08-19 12:49:41 +00008307 }
TatWai Chongd8c052a2016-11-02 16:12:48 +08008308 return callee_method;
8309}
8310
8311void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
8312 Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
Vladimir Marko58155012015-08-19 12:49:41 +00008313
8314 switch (invoke->GetCodePtrLocation()) {
8315 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
8316 __ bl(GetFrameEntryLabel());
8317 break;
Vladimir Marko58155012015-08-19 12:49:41 +00008318 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
8319 // LR = callee_method->entry_point_from_quick_compiled_code_
8320 __ LoadFromOffset(
8321 kLoadWord, LR, callee_method.AsRegister<Register>(),
Andreas Gampe542451c2016-07-26 09:02:02 -07008322 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00008323 // LR()
8324 __ blx(LR);
8325 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08008326 }
8327
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08008328 DCHECK(!IsLeafMethod());
8329}
8330
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008331void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
8332 Register temp = temp_location.AsRegister<Register>();
8333 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
8334 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00008335
8336 // Use the calling convention instead of the location of the receiver, as
8337 // intrinsics may have put the receiver in a different register. In the intrinsics
8338 // slow path, the arguments have been moved to the right place, so here we are
8339 // guaranteed that the receiver is the first register of the calling convention.
8340 InvokeDexCallingConvention calling_convention;
8341 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008342 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00008343 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00008344 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008345 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00008346 // Instead of simply (possibly) unpoisoning `temp` here, we should
8347 // emit a read barrier for the previous class reference load.
8348 // However this is not required in practice, as this is an
8349 // intermediate/temporary reference and because the current
8350 // concurrent copying collector keeps the from-space memory
8351 // intact/accessible until the end of the marking phase (the
8352 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008353 __ MaybeUnpoisonHeapReference(temp);
8354 // temp = temp->GetMethodAt(method_offset);
8355 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07008356 kArmPointerSize).Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008357 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
8358 // LR = temp->GetEntryPoint();
8359 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
8360 // LR();
8361 __ blx(LR);
8362}
8363
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008364CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008365 const DexFile& dex_file, dex::StringIndex string_index) {
8366 return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008367}
8368
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008369CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
Andreas Gampea5b09a62016-11-17 15:21:22 -08008370 const DexFile& dex_file, dex::TypeIndex type_index) {
8371 return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008372}
8373
Vladimir Marko1998cd02017-01-13 13:02:58 +00008374CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
8375 const DexFile& dex_file, dex::TypeIndex type_index) {
8376 return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
8377}
8378
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008379CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
8380 const DexFile& dex_file, uint32_t element_offset) {
8381 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
8382}
8383
8384CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
8385 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
8386 patches->emplace_back(dex_file, offset_or_index);
8387 return &patches->back();
8388}
8389
8390Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008391 dex::StringIndex string_index) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008392 return boot_image_string_patches_.GetOrCreate(
8393 StringReference(&dex_file, string_index),
8394 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8395}
8396
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008397Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08008398 dex::TypeIndex type_index) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008399 return boot_image_type_patches_.GetOrCreate(
8400 TypeReference(&dex_file, type_index),
8401 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8402}
8403
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008404Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
Richard Uhlerc52f3032017-03-02 13:45:45 +00008405 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008406}
8407
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008408Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00008409 dex::StringIndex string_index,
8410 Handle<mirror::String> handle) {
8411 jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
8412 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008413 return jit_string_patches_.GetOrCreate(
8414 StringReference(&dex_file, string_index),
8415 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8416}
8417
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008418Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
8419 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00008420 Handle<mirror::Class> handle) {
8421 jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
8422 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008423 return jit_class_patches_.GetOrCreate(
8424 TypeReference(&dex_file, type_index),
8425 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8426}
8427
Vladimir Markoaad75c62016-10-03 08:46:48 +00008428template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
8429inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
8430 const ArenaDeque<PcRelativePatchInfo>& infos,
8431 ArenaVector<LinkerPatch>* linker_patches) {
8432 for (const PcRelativePatchInfo& info : infos) {
8433 const DexFile& dex_file = info.target_dex_file;
8434 size_t offset_or_index = info.offset_or_index;
8435 DCHECK(info.add_pc_label.IsBound());
8436 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
8437 // Add MOVW patch.
8438 DCHECK(info.movw_label.IsBound());
8439 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
8440 linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
8441 // Add MOVT patch.
8442 DCHECK(info.movt_label.IsBound());
8443 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
8444 linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
8445 }
8446}
8447
Vladimir Marko58155012015-08-19 12:49:41 +00008448void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
8449 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00008450 size_t size =
Vladimir Markoaad75c62016-10-03 08:46:48 +00008451 /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008452 boot_image_string_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00008453 /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008454 boot_image_type_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00008455 /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
Richard Uhlerc52f3032017-03-02 13:45:45 +00008456 /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00008457 linker_patches->reserve(size);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008458 EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
8459 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008460 for (const auto& entry : boot_image_string_patches_) {
8461 const StringReference& target_string = entry.first;
8462 Literal* literal = entry.second;
8463 DCHECK(literal->GetLabel()->IsBound());
8464 uint32_t literal_offset = literal->GetLabel()->Position();
8465 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
8466 target_string.dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008467 target_string.string_index.index_));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008468 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00008469 if (!GetCompilerOptions().IsBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00008470 DCHECK(pc_relative_type_patches_.empty());
Vladimir Markoaad75c62016-10-03 08:46:48 +00008471 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
8472 linker_patches);
8473 } else {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008474 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
8475 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008476 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
8477 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008478 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00008479 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
8480 linker_patches);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008481 for (const auto& entry : boot_image_type_patches_) {
8482 const TypeReference& target_type = entry.first;
8483 Literal* literal = entry.second;
8484 DCHECK(literal->GetLabel()->IsBound());
8485 uint32_t literal_offset = literal->GetLabel()->Position();
8486 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
8487 target_type.dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08008488 target_type.type_index.index_));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008489 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00008490 DCHECK_EQ(size, linker_patches->size());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008491}
8492
8493Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
8494 return map->GetOrCreate(
8495 value,
8496 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00008497}
8498
8499Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
8500 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008501 return map->GetOrCreate(
8502 target_method,
8503 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00008504}
8505
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03008506void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8507 LocationSummary* locations =
8508 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
8509 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
8510 Location::RequiresRegister());
8511 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
8512 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
8513 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8514}
8515
8516void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8517 LocationSummary* locations = instr->GetLocations();
8518 Register res = locations->Out().AsRegister<Register>();
8519 Register accumulator =
8520 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
8521 Register mul_left =
8522 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
8523 Register mul_right =
8524 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
8525
8526 if (instr->GetOpKind() == HInstruction::kAdd) {
8527 __ mla(res, mul_left, mul_right, accumulator);
8528 } else {
8529 __ mls(res, mul_left, mul_right, accumulator);
8530 }
8531}
8532
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008533void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008534 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008535 LOG(FATAL) << "Unreachable";
8536}
8537
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008538void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008539 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008540 LOG(FATAL) << "Unreachable";
8541}
8542
Mark Mendellfe57faa2015-09-18 09:26:15 -04008543// Simple implementation of packed switch - generate cascaded compare/jumps.
8544void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8545 LocationSummary* locations =
8546 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8547 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008548 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008549 codegen_->GetAssembler()->IsThumb()) {
8550 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
8551 if (switch_instr->GetStartValue() != 0) {
8552 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
8553 }
8554 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04008555}
8556
8557void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8558 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008559 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04008560 LocationSummary* locations = switch_instr->GetLocations();
8561 Register value_reg = locations->InAt(0).AsRegister<Register>();
8562 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8563
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008564 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008565 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008566 Register temp_reg = IP;
8567 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
8568 // the immediate, because IP is used as the destination register. For the other
8569 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
8570 // and they can be encoded in the instruction without making use of IP register.
8571 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
8572
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008573 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008574 // Jump to successors[0] if value == lower_bound.
8575 __ b(codegen_->GetLabelOf(successors[0]), EQ);
8576 int32_t last_index = 0;
8577 for (; num_entries - last_index > 2; last_index += 2) {
8578 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
8579 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
8580 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
8581 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
8582 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
8583 }
8584 if (num_entries - last_index == 2) {
8585 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00008586 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008587 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008588 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04008589
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008590 // And the default for any other value.
8591 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
8592 __ b(codegen_->GetLabelOf(default_block));
8593 }
8594 } else {
8595 // Create a table lookup.
8596 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
8597
8598 // Materialize a pointer to the switch table
8599 std::vector<Label*> labels(num_entries);
8600 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
8601 for (uint32_t i = 0; i < num_entries; i++) {
8602 labels[i] = codegen_->GetLabelOf(successors[i]);
8603 }
8604 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
8605
8606 // Remove the bias.
8607 Register key_reg;
8608 if (lower_bound != 0) {
8609 key_reg = locations->GetTemp(1).AsRegister<Register>();
8610 __ AddConstant(key_reg, value_reg, -lower_bound);
8611 } else {
8612 key_reg = value_reg;
8613 }
8614
8615 // Check whether the value is in the table, jump to default block if not.
8616 __ CmpConstant(key_reg, num_entries - 1);
8617 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
8618
8619 // Load the displacement from the table.
8620 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
8621
8622 // Dispatch is a direct add to the PC (for Thumb2).
8623 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04008624 }
8625}
8626
Vladimir Markob4536b72015-11-24 13:45:23 +00008627void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8628 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
8629 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00008630}
8631
8632void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8633 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008634 CodeGeneratorARM::PcRelativePatchInfo* labels =
8635 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00008636 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008637 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00008638 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008639 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00008640 __ BindTrackedLabel(&labels->add_pc_label);
8641 __ add(base_reg, base_reg, ShifterOperand(PC));
8642}
8643
Andreas Gampe85b62f22015-09-09 13:15:38 -07008644void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
8645 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00008646 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07008647 return;
8648 }
8649
8650 DCHECK_NE(type, Primitive::kPrimVoid);
8651
8652 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
8653 if (return_loc.Equals(trg)) {
8654 return;
8655 }
8656
8657 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
8658 // with the last branch.
8659 if (type == Primitive::kPrimLong) {
8660 HParallelMove parallel_move(GetGraph()->GetArena());
8661 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
8662 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
8663 GetMoveResolver()->EmitNativeCode(&parallel_move);
8664 } else if (type == Primitive::kPrimDouble) {
8665 HParallelMove parallel_move(GetGraph()->GetArena());
8666 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
8667 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
8668 GetMoveResolver()->EmitNativeCode(&parallel_move);
8669 } else {
8670 // Let the parallel move resolver take care of all of this.
8671 HParallelMove parallel_move(GetGraph()->GetArena());
8672 parallel_move.AddMove(return_loc, trg, type, nullptr);
8673 GetMoveResolver()->EmitNativeCode(&parallel_move);
8674 }
8675}
8676
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00008677void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
8678 LocationSummary* locations =
8679 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
8680 locations->SetInAt(0, Location::RequiresRegister());
8681 locations->SetOut(Location::RequiresRegister());
8682}
8683
8684void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
8685 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00008686 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01008687 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00008688 instruction->GetIndex(), kArmPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01008689 __ LoadFromOffset(kLoadWord,
8690 locations->Out().AsRegister<Register>(),
8691 locations->InAt(0).AsRegister<Register>(),
8692 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00008693 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01008694 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00008695 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01008696 __ LoadFromOffset(kLoadWord,
8697 locations->Out().AsRegister<Register>(),
8698 locations->InAt(0).AsRegister<Register>(),
8699 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
8700 __ LoadFromOffset(kLoadWord,
8701 locations->Out().AsRegister<Register>(),
8702 locations->Out().AsRegister<Register>(),
8703 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00008704 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00008705}
8706
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008707static void PatchJitRootUse(uint8_t* code,
8708 const uint8_t* roots_data,
8709 Literal* literal,
8710 uint64_t index_in_table) {
8711 DCHECK(literal->GetLabel()->IsBound());
8712 uint32_t literal_offset = literal->GetLabel()->Position();
8713 uintptr_t address =
8714 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
8715 uint8_t* data = code + literal_offset;
8716 reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
8717}
8718
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008719void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
8720 for (const auto& entry : jit_string_patches_) {
8721 const auto& it = jit_string_roots_.find(entry.first);
8722 DCHECK(it != jit_string_roots_.end());
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008723 PatchJitRootUse(code, roots_data, entry.second, it->second);
8724 }
8725 for (const auto& entry : jit_class_patches_) {
8726 const auto& it = jit_class_roots_.find(entry.first);
8727 DCHECK(it != jit_class_roots_.end());
8728 PatchJitRootUse(code, roots_data, entry.second, it->second);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008729 }
8730}
8731
Roland Levillain4d027112015-07-01 15:41:14 +01008732#undef __
8733#undef QUICK_ENTRY_POINT
8734
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00008735} // namespace arm
8736} // namespace art