blob: 030b91c11507f331bb26a03b8c80a8e30056ba94 [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());
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100588 arm_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000589 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700590 }
591
Alexandre Rames9931f312015-06-19 14:47:01 +0100592 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
593
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700594 private:
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700595 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
596};
597
Artem Serovf4d6aee2016-07-11 10:41:45 +0100598class ArraySetSlowPathARM : public SlowPathCodeARM {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100599 public:
Artem Serovf4d6aee2016-07-11 10:41:45 +0100600 explicit ArraySetSlowPathARM(HInstruction* instruction) : SlowPathCodeARM(instruction) {}
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100601
602 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
603 LocationSummary* locations = instruction_->GetLocations();
604 __ Bind(GetEntryLabel());
605 SaveLiveRegisters(codegen, locations);
606
607 InvokeRuntimeCallingConvention calling_convention;
608 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
609 parallel_move.AddMove(
610 locations->InAt(0),
611 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
612 Primitive::kPrimNot,
613 nullptr);
614 parallel_move.AddMove(
615 locations->InAt(1),
616 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
617 Primitive::kPrimInt,
618 nullptr);
619 parallel_move.AddMove(
620 locations->InAt(2),
621 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
622 Primitive::kPrimNot,
623 nullptr);
624 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
625
626 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +0100627 arm_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000628 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100629 RestoreLiveRegisters(codegen, locations);
630 __ b(GetExitLabel());
631 }
632
633 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathARM"; }
634
635 private:
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +0100636 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathARM);
637};
638
Roland Levillain54f869e2017-03-06 13:54:11 +0000639// Abstract base class for read barrier slow paths marking a reference
640// `ref`.
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000641//
Roland Levillain54f869e2017-03-06 13:54:11 +0000642// Argument `entrypoint` must be a register location holding the read
643// barrier marking runtime entry point to be invoked.
644class ReadBarrierMarkSlowPathBaseARM : public SlowPathCodeARM {
645 protected:
646 ReadBarrierMarkSlowPathBaseARM(HInstruction* instruction, Location ref, Location entrypoint)
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000647 : SlowPathCodeARM(instruction), ref_(ref), entrypoint_(entrypoint) {
648 DCHECK(kEmitCompilerReadBarrier);
649 }
650
Roland Levillain54f869e2017-03-06 13:54:11 +0000651 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathBaseARM"; }
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000652
Roland Levillain54f869e2017-03-06 13:54:11 +0000653 // Generate assembly code calling the read barrier marking runtime
654 // entry point (ReadBarrierMarkRegX).
655 void GenerateReadBarrierMarkRuntimeCall(CodeGenerator* codegen) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000656 Register ref_reg = ref_.AsRegister<Register>();
Roland Levillain47b3ab22017-02-27 14:31:35 +0000657
Roland Levillain47b3ab22017-02-27 14:31:35 +0000658 // No need to save live registers; it's taken care of by the
659 // entrypoint. Also, there is no need to update the stack mask,
660 // as this runtime call will not trigger a garbage collection.
661 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
662 DCHECK_NE(ref_reg, SP);
663 DCHECK_NE(ref_reg, LR);
664 DCHECK_NE(ref_reg, PC);
665 // IP is used internally by the ReadBarrierMarkRegX entry point
666 // as a temporary, it cannot be the entry point's input/output.
667 DCHECK_NE(ref_reg, IP);
668 DCHECK(0 <= ref_reg && ref_reg < kNumberOfCoreRegisters) << ref_reg;
669 // "Compact" slow path, saving two moves.
670 //
671 // Instead of using the standard runtime calling convention (input
672 // and output in R0):
673 //
674 // R0 <- ref
675 // R0 <- ReadBarrierMark(R0)
676 // ref <- R0
677 //
678 // we just use rX (the register containing `ref`) as input and output
679 // of a dedicated entrypoint:
680 //
681 // rX <- ReadBarrierMarkRegX(rX)
682 //
683 if (entrypoint_.IsValid()) {
684 arm_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
685 __ blx(entrypoint_.AsRegister<Register>());
686 } else {
Roland Levillain54f869e2017-03-06 13:54:11 +0000687 // Entrypoint is not already loaded, load from the thread.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000688 int32_t entry_point_offset =
689 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref_reg);
690 // This runtime call does not require a stack map.
691 arm_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset, instruction_, this);
692 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000693 }
694
695 // The location (register) of the marked object reference.
696 const Location ref_;
697
698 // The location of the entrypoint if it is already loaded.
699 const Location entrypoint_;
700
701 private:
702 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathBaseARM);
703};
704
Dave Allison20dfc792014-06-16 20:44:29 -0700705// Slow path marking an object reference `ref` during a read
706// barrier. The field `obj.field` in the object `obj` holding this
Roland Levillain54f869e2017-03-06 13:54:11 +0000707// reference does not get updated by this slow path after marking.
Dave Allison20dfc792014-06-16 20:44:29 -0700708//
709// This means that after the execution of this slow path, `ref` will
710// always be up-to-date, but `obj.field` may not; i.e., after the
711// flip, `ref` will be a to-space reference, but `obj.field` will
712// probably still be a from-space reference (unless it gets updated by
713// another thread, or if another thread installed another object
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000714// reference (different from `ref`) in `obj.field`).
715//
716// If `entrypoint` is a valid location it is assumed to already be
717// holding the entrypoint. The case where the entrypoint is passed in
Roland Levillainba650a42017-03-06 13:52:32 +0000718// is when the decision to mark is based on whether the GC is marking.
Roland Levillain54f869e2017-03-06 13:54:11 +0000719class ReadBarrierMarkSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000720 public:
721 ReadBarrierMarkSlowPathARM(HInstruction* instruction,
722 Location ref,
723 Location entrypoint = Location::NoLocation())
Roland Levillain54f869e2017-03-06 13:54:11 +0000724 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint) {
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000725 DCHECK(kEmitCompilerReadBarrier);
726 }
727
728 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathARM"; }
729
730 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
731 LocationSummary* locations = instruction_->GetLocations();
Roland Levillain54f869e2017-03-06 13:54:11 +0000732 DCHECK(locations->CanCall());
733 if (kIsDebugBuild) {
734 Register ref_reg = ref_.AsRegister<Register>();
735 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
736 }
737 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
738 << "Unexpected instruction in read barrier marking slow path: "
739 << instruction_->DebugName();
740
741 __ Bind(GetEntryLabel());
742 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000743 __ b(GetExitLabel());
744 }
745
746 private:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000747 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
748};
749
Roland Levillain54f869e2017-03-06 13:54:11 +0000750// Slow path loading `obj`'s lock word, loading a reference from
751// object `*(obj + offset + (index << scale_factor))` into `ref`, and
752// marking `ref` if `obj` is gray according to the lock word (Baker
753// read barrier). The field `obj.field` in the object `obj` holding
754// this reference does not get updated by this slow path after marking
755// (see LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
756// below for that).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000757//
Roland Levillain54f869e2017-03-06 13:54:11 +0000758// This means that after the execution of this slow path, `ref` will
759// always be up-to-date, but `obj.field` may not; i.e., after the
760// flip, `ref` will be a to-space reference, but `obj.field` will
761// probably still be a from-space reference (unless it gets updated by
762// another thread, or if another thread installed another object
763// reference (different from `ref`) in `obj.field`).
764//
765// Argument `entrypoint` must be a register location holding the read
766// barrier marking runtime entry point to be invoked.
767class LoadReferenceWithBakerReadBarrierSlowPathARM : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000768 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000769 LoadReferenceWithBakerReadBarrierSlowPathARM(HInstruction* instruction,
770 Location ref,
771 Register obj,
772 uint32_t offset,
773 Location index,
774 ScaleFactor scale_factor,
775 bool needs_null_check,
776 Register temp,
777 Location entrypoint)
778 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000779 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000780 offset_(offset),
781 index_(index),
782 scale_factor_(scale_factor),
783 needs_null_check_(needs_null_check),
784 temp_(temp) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000785 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000786 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000787 }
788
Roland Levillain54f869e2017-03-06 13:54:11 +0000789 const char* GetDescription() const OVERRIDE {
790 return "LoadReferenceWithBakerReadBarrierSlowPathARM";
791 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000792
793 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
794 LocationSummary* locations = instruction_->GetLocations();
795 Register ref_reg = ref_.AsRegister<Register>();
796 DCHECK(locations->CanCall());
797 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000798 DCHECK_NE(ref_reg, temp_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000799 DCHECK(instruction_->IsInstanceFieldGet() ||
800 instruction_->IsStaticFieldGet() ||
801 instruction_->IsArrayGet() ||
802 instruction_->IsArraySet() ||
Roland Levillain47b3ab22017-02-27 14:31:35 +0000803 instruction_->IsInstanceOf() ||
804 instruction_->IsCheckCast() ||
805 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
806 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
807 << "Unexpected instruction in read barrier marking slow path: "
808 << instruction_->DebugName();
809 // The read barrier instrumentation of object ArrayGet
810 // instructions does not support the HIntermediateAddress
811 // instruction.
812 DCHECK(!(instruction_->IsArrayGet() &&
813 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
814
815 __ Bind(GetEntryLabel());
Roland Levillain54f869e2017-03-06 13:54:11 +0000816
817 // When using MaybeGenerateReadBarrierSlow, the read barrier call is
818 // inserted after the original load. However, in fast path based
819 // Baker's read barriers, we need to perform the load of
820 // mirror::Object::monitor_ *before* the original reference load.
821 // This load-load ordering is required by the read barrier.
822 // The fast path/slow path (for Baker's algorithm) should look like:
Roland Levillain47b3ab22017-02-27 14:31:35 +0000823 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000824 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
825 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
826 // HeapReference<mirror::Object> ref = *src; // Original reference load.
827 // bool is_gray = (rb_state == ReadBarrier::GrayState());
828 // if (is_gray) {
829 // ref = entrypoint(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
830 // }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000831 //
Roland Levillain54f869e2017-03-06 13:54:11 +0000832 // Note: the original implementation in ReadBarrier::Barrier is
833 // slightly more complex as it performs additional checks that we do
834 // not do here for performance reasons.
835
836 // /* int32_t */ monitor = obj->monitor_
837 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
838 __ LoadFromOffset(kLoadWord, temp_, obj_, monitor_offset);
839 if (needs_null_check_) {
840 codegen->MaybeRecordImplicitNullCheck(instruction_);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000841 }
Roland Levillain54f869e2017-03-06 13:54:11 +0000842 // /* LockWord */ lock_word = LockWord(monitor)
843 static_assert(sizeof(LockWord) == sizeof(int32_t),
844 "art::LockWord and int32_t have different sizes.");
845
846 // Introduce a dependency on the lock_word including the rb_state,
847 // which shall prevent load-load reordering without using
848 // a memory barrier (which would be more expensive).
849 // `obj` is unchanged by this operation, but its value now depends
850 // on `temp`.
851 __ add(obj_, obj_, ShifterOperand(temp_, LSR, 32));
852
853 // The actual reference load.
854 // A possible implicit null check has already been handled above.
855 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
856 arm_codegen->GenerateRawReferenceLoad(
857 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
858
859 // Mark the object `ref` when `obj` is gray.
860 //
861 // if (rb_state == ReadBarrier::GrayState())
862 // ref = ReadBarrier::Mark(ref);
863 //
864 // Given the numeric representation, it's enough to check the low bit of the
865 // rb_state. We do that by shifting the bit out of the lock word with LSRS
866 // which can be a 16-bit instruction unlike the TST immediate.
867 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
868 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
869 __ Lsrs(temp_, temp_, LockWord::kReadBarrierStateShift + 1);
870 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
871 GenerateReadBarrierMarkRuntimeCall(codegen);
872
Roland Levillain47b3ab22017-02-27 14:31:35 +0000873 __ b(GetExitLabel());
874 }
875
876 private:
Roland Levillain54f869e2017-03-06 13:54:11 +0000877 // The register containing the object holding the marked object reference field.
878 Register obj_;
879 // The offset, index and scale factor to access the reference in `obj_`.
880 uint32_t offset_;
881 Location index_;
882 ScaleFactor scale_factor_;
883 // Is a null check required?
884 bool needs_null_check_;
885 // A temporary register used to hold the lock word of `obj_`.
886 Register temp_;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000887
Roland Levillain54f869e2017-03-06 13:54:11 +0000888 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierSlowPathARM);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000889};
890
Roland Levillain54f869e2017-03-06 13:54:11 +0000891// Slow path loading `obj`'s lock word, loading a reference from
892// object `*(obj + offset + (index << scale_factor))` into `ref`, and
893// marking `ref` if `obj` is gray according to the lock word (Baker
894// read barrier). If needed, this slow path also atomically updates
895// the field `obj.field` in the object `obj` holding this reference
896// after marking (contrary to
897// LoadReferenceWithBakerReadBarrierSlowPathARM above, which never
898// tries to update `obj.field`).
Roland Levillain47b3ab22017-02-27 14:31:35 +0000899//
900// This means that after the execution of this slow path, both `ref`
901// and `obj.field` will be up-to-date; i.e., after the flip, both will
902// hold the same to-space reference (unless another thread installed
903// another object reference (different from `ref`) in `obj.field`).
Roland Levillainba650a42017-03-06 13:52:32 +0000904//
Roland Levillain54f869e2017-03-06 13:54:11 +0000905// Argument `entrypoint` must be a register location holding the read
906// barrier marking runtime entry point to be invoked.
907class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM
908 : public ReadBarrierMarkSlowPathBaseARM {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000909 public:
Roland Levillain54f869e2017-03-06 13:54:11 +0000910 LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(HInstruction* instruction,
911 Location ref,
912 Register obj,
913 uint32_t offset,
914 Location index,
915 ScaleFactor scale_factor,
916 bool needs_null_check,
917 Register temp1,
918 Register temp2,
919 Location entrypoint)
920 : ReadBarrierMarkSlowPathBaseARM(instruction, ref, entrypoint),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000921 obj_(obj),
Roland Levillain54f869e2017-03-06 13:54:11 +0000922 offset_(offset),
923 index_(index),
924 scale_factor_(scale_factor),
925 needs_null_check_(needs_null_check),
Roland Levillain47b3ab22017-02-27 14:31:35 +0000926 temp1_(temp1),
Roland Levillain54f869e2017-03-06 13:54:11 +0000927 temp2_(temp2) {
Roland Levillain47b3ab22017-02-27 14:31:35 +0000928 DCHECK(kEmitCompilerReadBarrier);
Roland Levillain54f869e2017-03-06 13:54:11 +0000929 DCHECK(kUseBakerReadBarrier);
Roland Levillain47b3ab22017-02-27 14:31:35 +0000930 }
931
Roland Levillain54f869e2017-03-06 13:54:11 +0000932 const char* GetDescription() const OVERRIDE {
933 return "LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM";
934 }
Roland Levillain47b3ab22017-02-27 14:31:35 +0000935
936 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
937 LocationSummary* locations = instruction_->GetLocations();
938 Register ref_reg = ref_.AsRegister<Register>();
939 DCHECK(locations->CanCall());
940 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
Roland Levillain54f869e2017-03-06 13:54:11 +0000941 DCHECK_NE(ref_reg, temp1_);
942
943 // This slow path is only used by the UnsafeCASObject intrinsic at the moment.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000944 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
945 << "Unexpected instruction in read barrier marking and field updating slow path: "
946 << instruction_->DebugName();
947 DCHECK(instruction_->GetLocations()->Intrinsified());
948 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
Roland Levillain54f869e2017-03-06 13:54:11 +0000949 DCHECK_EQ(offset_, 0u);
950 DCHECK_EQ(scale_factor_, ScaleFactor::TIMES_1);
951 // The location of the offset of the marked reference field within `obj_`.
952 Location field_offset = index_;
953 DCHECK(field_offset.IsRegisterPair()) << field_offset;
Roland Levillain47b3ab22017-02-27 14:31:35 +0000954
955 __ Bind(GetEntryLabel());
956
Roland Levillain54f869e2017-03-06 13:54:11 +0000957 // /* int32_t */ monitor = obj->monitor_
958 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
959 __ LoadFromOffset(kLoadWord, temp1_, obj_, monitor_offset);
960 if (needs_null_check_) {
961 codegen->MaybeRecordImplicitNullCheck(instruction_);
962 }
963 // /* LockWord */ lock_word = LockWord(monitor)
964 static_assert(sizeof(LockWord) == sizeof(int32_t),
965 "art::LockWord and int32_t have different sizes.");
966
967 // Introduce a dependency on the lock_word including the rb_state,
968 // which shall prevent load-load reordering without using
969 // a memory barrier (which would be more expensive).
970 // `obj` is unchanged by this operation, but its value now depends
971 // on `temp1`.
972 __ add(obj_, obj_, ShifterOperand(temp1_, LSR, 32));
973
974 // The actual reference load.
975 // A possible implicit null check has already been handled above.
976 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
977 arm_codegen->GenerateRawReferenceLoad(
978 instruction_, ref_, obj_, offset_, index_, scale_factor_, /* needs_null_check */ false);
979
980 // Mark the object `ref` when `obj` is gray.
981 //
982 // if (rb_state == ReadBarrier::GrayState())
983 // ref = ReadBarrier::Mark(ref);
984 //
985 // Given the numeric representation, it's enough to check the low bit of the
986 // rb_state. We do that by shifting the bit out of the lock word with LSRS
987 // which can be a 16-bit instruction unlike the TST immediate.
988 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
989 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
990 __ Lsrs(temp1_, temp1_, LockWord::kReadBarrierStateShift + 1);
991 __ b(GetExitLabel(), CC); // Carry flag is the last bit shifted out by LSRS.
992
993 // Save the old value of the reference before marking it.
Roland Levillain47b3ab22017-02-27 14:31:35 +0000994 // Note that we cannot use IP to save the old reference, as IP is
995 // used internally by the ReadBarrierMarkRegX entry point, and we
996 // need the old reference after the call to that entry point.
997 DCHECK_NE(temp1_, IP);
998 __ Mov(temp1_, ref_reg);
Roland Levillain27b1f9c2017-01-17 16:56:34 +0000999
Roland Levillain54f869e2017-03-06 13:54:11 +00001000 GenerateReadBarrierMarkRuntimeCall(codegen);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001001
1002 // If the new reference is different from the old reference,
Roland Levillain54f869e2017-03-06 13:54:11 +00001003 // update the field in the holder (`*(obj_ + field_offset)`).
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001004 //
1005 // Note that this field could also hold a different object, if
1006 // another thread had concurrently changed it. In that case, the
1007 // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set
1008 // (CAS) operation below would abort the CAS, leaving the field
1009 // as-is.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001010 __ cmp(temp1_, ShifterOperand(ref_reg));
Roland Levillain54f869e2017-03-06 13:54:11 +00001011 __ b(GetExitLabel(), EQ);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001012
1013 // Update the the holder's field atomically. This may fail if
1014 // mutator updates before us, but it's OK. This is achieved
1015 // using a strong compare-and-set (CAS) operation with relaxed
1016 // memory synchronization ordering, where the expected value is
1017 // the old reference and the desired value is the new reference.
1018
1019 // Convenience aliases.
1020 Register base = obj_;
1021 // The UnsafeCASObject intrinsic uses a register pair as field
1022 // offset ("long offset"), of which only the low part contains
1023 // data.
Roland Levillain54f869e2017-03-06 13:54:11 +00001024 Register offset = field_offset.AsRegisterPairLow<Register>();
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001025 Register expected = temp1_;
1026 Register value = ref_reg;
1027 Register tmp_ptr = IP; // Pointer to actual memory.
1028 Register tmp = temp2_; // Value in memory.
1029
1030 __ add(tmp_ptr, base, ShifterOperand(offset));
1031
1032 if (kPoisonHeapReferences) {
1033 __ PoisonHeapReference(expected);
1034 if (value == expected) {
1035 // Do not poison `value`, as it is the same register as
1036 // `expected`, which has just been poisoned.
1037 } else {
1038 __ PoisonHeapReference(value);
1039 }
1040 }
1041
1042 // do {
1043 // tmp = [r_ptr] - expected;
1044 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
1045
Roland Levillain24a4d112016-10-26 13:10:46 +01001046 Label loop_head, exit_loop;
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001047 __ Bind(&loop_head);
1048
1049 __ ldrex(tmp, tmp_ptr);
1050
1051 __ subs(tmp, tmp, ShifterOperand(expected));
1052
Roland Levillain24a4d112016-10-26 13:10:46 +01001053 __ it(NE);
1054 __ clrex(NE);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001055
Roland Levillain24a4d112016-10-26 13:10:46 +01001056 __ b(&exit_loop, NE);
1057
1058 __ strex(tmp, value, tmp_ptr);
1059 __ cmp(tmp, ShifterOperand(1));
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001060 __ b(&loop_head, EQ);
1061
Roland Levillain24a4d112016-10-26 13:10:46 +01001062 __ Bind(&exit_loop);
1063
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001064 if (kPoisonHeapReferences) {
1065 __ UnpoisonHeapReference(expected);
1066 if (value == expected) {
1067 // Do not unpoison `value`, as it is the same register as
1068 // `expected`, which has just been unpoisoned.
1069 } else {
1070 __ UnpoisonHeapReference(value);
1071 }
1072 }
1073
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001074 __ b(GetExitLabel());
1075 }
1076
1077 private:
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001078 // The register containing the object holding the marked object reference field.
1079 const Register obj_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001080 // The offset, index and scale factor to access the reference in `obj_`.
1081 uint32_t offset_;
1082 Location index_;
1083 ScaleFactor scale_factor_;
1084 // Is a null check required?
1085 bool needs_null_check_;
1086 // A temporary register used to hold the lock word of `obj_`; and
1087 // also to hold the original reference value, when the reference is
1088 // marked.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001089 const Register temp1_;
Roland Levillain54f869e2017-03-06 13:54:11 +00001090 // A temporary register used in the implementation of the CAS, to
1091 // update the object's reference field.
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001092 const Register temp2_;
1093
Roland Levillain54f869e2017-03-06 13:54:11 +00001094 DISALLOW_COPY_AND_ASSIGN(LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM);
Roland Levillaina1aa3b12016-10-26 13:03:38 +01001095};
1096
Roland Levillain3b359c72015-11-17 19:35:12 +00001097// Slow path generating a read barrier for a heap reference.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001098class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001099 public:
1100 ReadBarrierForHeapReferenceSlowPathARM(HInstruction* instruction,
1101 Location out,
1102 Location ref,
1103 Location obj,
1104 uint32_t offset,
1105 Location index)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001106 : SlowPathCodeARM(instruction),
Roland Levillain3b359c72015-11-17 19:35:12 +00001107 out_(out),
1108 ref_(ref),
1109 obj_(obj),
1110 offset_(offset),
1111 index_(index) {
1112 DCHECK(kEmitCompilerReadBarrier);
1113 // If `obj` is equal to `out` or `ref`, it means the initial object
1114 // has been overwritten by (or after) the heap object reference load
1115 // to be instrumented, e.g.:
1116 //
1117 // __ LoadFromOffset(kLoadWord, out, out, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00001118 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00001119 //
1120 // In that case, we have lost the information about the original
1121 // object, and the emitted read barrier cannot work properly.
1122 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
1123 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
1124 }
1125
1126 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1127 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1128 LocationSummary* locations = instruction_->GetLocations();
1129 Register reg_out = out_.AsRegister<Register>();
1130 DCHECK(locations->CanCall());
1131 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillain3d312422016-06-23 13:53:42 +01001132 DCHECK(instruction_->IsInstanceFieldGet() ||
1133 instruction_->IsStaticFieldGet() ||
1134 instruction_->IsArrayGet() ||
1135 instruction_->IsInstanceOf() ||
1136 instruction_->IsCheckCast() ||
Andreas Gamped9911ee2017-03-27 13:27:24 -07001137 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
Roland Levillainc9285912015-12-18 10:38:42 +00001138 << "Unexpected instruction in read barrier for heap reference slow path: "
1139 << instruction_->DebugName();
Roland Levillain19c54192016-11-04 13:44:09 +00001140 // The read barrier instrumentation of object ArrayGet
1141 // instructions does not support the HIntermediateAddress
1142 // instruction.
1143 DCHECK(!(instruction_->IsArrayGet() &&
1144 instruction_->AsArrayGet()->GetArray()->IsIntermediateAddress()));
Roland Levillain3b359c72015-11-17 19:35:12 +00001145
1146 __ Bind(GetEntryLabel());
1147 SaveLiveRegisters(codegen, locations);
1148
1149 // We may have to change the index's value, but as `index_` is a
1150 // constant member (like other "inputs" of this slow path),
1151 // introduce a copy of it, `index`.
1152 Location index = index_;
1153 if (index_.IsValid()) {
Roland Levillain3d312422016-06-23 13:53:42 +01001154 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
Roland Levillain3b359c72015-11-17 19:35:12 +00001155 if (instruction_->IsArrayGet()) {
1156 // Compute the actual memory offset and store it in `index`.
1157 Register index_reg = index_.AsRegister<Register>();
1158 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
1159 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
1160 // We are about to change the value of `index_reg` (see the
1161 // calls to art::arm::Thumb2Assembler::Lsl and
1162 // art::arm::Thumb2Assembler::AddConstant below), but it has
1163 // not been saved by the previous call to
1164 // art::SlowPathCode::SaveLiveRegisters, as it is a
1165 // callee-save register --
1166 // art::SlowPathCode::SaveLiveRegisters does not consider
1167 // callee-save registers, as it has been designed with the
1168 // assumption that callee-save registers are supposed to be
1169 // handled by the called function. So, as a callee-save
1170 // register, `index_reg` _would_ eventually be saved onto
1171 // the stack, but it would be too late: we would have
1172 // changed its value earlier. Therefore, we manually save
1173 // it here into another freely available register,
1174 // `free_reg`, chosen of course among the caller-save
1175 // registers (as a callee-save `free_reg` register would
1176 // exhibit the same problem).
1177 //
1178 // Note we could have requested a temporary register from
1179 // the register allocator instead; but we prefer not to, as
1180 // this is a slow path, and we know we can find a
1181 // caller-save register that is available.
1182 Register free_reg = FindAvailableCallerSaveRegister(codegen);
1183 __ Mov(free_reg, index_reg);
1184 index_reg = free_reg;
1185 index = Location::RegisterLocation(index_reg);
1186 } else {
1187 // The initial register stored in `index_` has already been
1188 // saved in the call to art::SlowPathCode::SaveLiveRegisters
1189 // (as it is not a callee-save register), so we can freely
1190 // use it.
1191 }
1192 // Shifting the index value contained in `index_reg` by the scale
1193 // factor (2) cannot overflow in practice, as the runtime is
1194 // unable to allocate object arrays with a size larger than
1195 // 2^26 - 1 (that is, 2^28 - 4 bytes).
1196 __ Lsl(index_reg, index_reg, TIMES_4);
1197 static_assert(
1198 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
1199 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
1200 __ AddConstant(index_reg, index_reg, offset_);
1201 } else {
Roland Levillain3d312422016-06-23 13:53:42 +01001202 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
1203 // intrinsics, `index_` is not shifted by a scale factor of 2
1204 // (as in the case of ArrayGet), as it is actually an offset
1205 // to an object field within an object.
1206 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001207 DCHECK(instruction_->GetLocations()->Intrinsified());
1208 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
1209 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
1210 << instruction_->AsInvoke()->GetIntrinsic();
1211 DCHECK_EQ(offset_, 0U);
1212 DCHECK(index_.IsRegisterPair());
1213 // UnsafeGet's offset location is a register pair, the low
1214 // part contains the correct offset.
1215 index = index_.ToLow();
1216 }
1217 }
1218
1219 // We're moving two or three locations to locations that could
1220 // overlap, so we need a parallel move resolver.
1221 InvokeRuntimeCallingConvention calling_convention;
1222 HParallelMove parallel_move(codegen->GetGraph()->GetArena());
1223 parallel_move.AddMove(ref_,
1224 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
1225 Primitive::kPrimNot,
1226 nullptr);
1227 parallel_move.AddMove(obj_,
1228 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
1229 Primitive::kPrimNot,
1230 nullptr);
1231 if (index.IsValid()) {
1232 parallel_move.AddMove(index,
1233 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
1234 Primitive::kPrimInt,
1235 nullptr);
1236 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1237 } else {
1238 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
1239 __ LoadImmediate(calling_convention.GetRegisterAt(2), offset_);
1240 }
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001241 arm_codegen->InvokeRuntime(kQuickReadBarrierSlow, instruction_, instruction_->GetDexPc(), this);
Roland Levillain3b359c72015-11-17 19:35:12 +00001242 CheckEntrypointTypes<
1243 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
1244 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1245
1246 RestoreLiveRegisters(codegen, locations);
1247 __ b(GetExitLabel());
1248 }
1249
1250 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathARM"; }
1251
1252 private:
1253 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
1254 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
1255 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
1256 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
1257 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) {
1258 return static_cast<Register>(i);
1259 }
1260 }
1261 // We shall never fail to find a free caller-save register, as
1262 // there are more than two core caller-save registers on ARM
1263 // (meaning it is possible to find one which is different from
1264 // `ref` and `obj`).
1265 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
1266 LOG(FATAL) << "Could not find a free caller-save register";
1267 UNREACHABLE();
1268 }
1269
Roland Levillain3b359c72015-11-17 19:35:12 +00001270 const Location out_;
1271 const Location ref_;
1272 const Location obj_;
1273 const uint32_t offset_;
1274 // An additional location containing an index to an array.
1275 // Only used for HArrayGet and the UnsafeGetObject &
1276 // UnsafeGetObjectVolatile intrinsics.
1277 const Location index_;
1278
1279 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathARM);
1280};
1281
1282// Slow path generating a read barrier for a GC root.
Artem Serovf4d6aee2016-07-11 10:41:45 +01001283class ReadBarrierForRootSlowPathARM : public SlowPathCodeARM {
Roland Levillain3b359c72015-11-17 19:35:12 +00001284 public:
1285 ReadBarrierForRootSlowPathARM(HInstruction* instruction, Location out, Location root)
Artem Serovf4d6aee2016-07-11 10:41:45 +01001286 : SlowPathCodeARM(instruction), out_(out), root_(root) {
Roland Levillainc9285912015-12-18 10:38:42 +00001287 DCHECK(kEmitCompilerReadBarrier);
1288 }
Roland Levillain3b359c72015-11-17 19:35:12 +00001289
1290 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
1291 LocationSummary* locations = instruction_->GetLocations();
1292 Register reg_out = out_.AsRegister<Register>();
1293 DCHECK(locations->CanCall());
1294 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
Roland Levillainc9285912015-12-18 10:38:42 +00001295 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
1296 << "Unexpected instruction in read barrier for GC root slow path: "
1297 << instruction_->DebugName();
Roland Levillain3b359c72015-11-17 19:35:12 +00001298
1299 __ Bind(GetEntryLabel());
1300 SaveLiveRegisters(codegen, locations);
1301
1302 InvokeRuntimeCallingConvention calling_convention;
1303 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
1304 arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01001305 arm_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
Roland Levillain3b359c72015-11-17 19:35:12 +00001306 instruction_,
1307 instruction_->GetDexPc(),
1308 this);
1309 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
1310 arm_codegen->Move32(out_, Location::RegisterLocation(R0));
1311
1312 RestoreLiveRegisters(codegen, locations);
1313 __ b(GetExitLabel());
1314 }
1315
1316 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathARM"; }
1317
1318 private:
Roland Levillain3b359c72015-11-17 19:35:12 +00001319 const Location out_;
1320 const Location root_;
1321
1322 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathARM);
1323};
1324
Aart Bike9f37602015-10-09 11:15:55 -07001325inline Condition ARMCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001326 switch (cond) {
1327 case kCondEQ: return EQ;
1328 case kCondNE: return NE;
1329 case kCondLT: return LT;
1330 case kCondLE: return LE;
1331 case kCondGT: return GT;
1332 case kCondGE: return GE;
Aart Bike9f37602015-10-09 11:15:55 -07001333 case kCondB: return LO;
1334 case kCondBE: return LS;
1335 case kCondA: return HI;
1336 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001337 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001338 LOG(FATAL) << "Unreachable";
1339 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001340}
1341
Aart Bike9f37602015-10-09 11:15:55 -07001342// Maps signed condition to unsigned condition.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001343inline Condition ARMUnsignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -07001344 switch (cond) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001345 case kCondEQ: return EQ;
1346 case kCondNE: return NE;
Aart Bike9f37602015-10-09 11:15:55 -07001347 // Signed to unsigned.
Roland Levillain4fa13f62015-07-06 18:11:54 +01001348 case kCondLT: return LO;
1349 case kCondLE: return LS;
1350 case kCondGT: return HI;
1351 case kCondGE: return HS;
Aart Bike9f37602015-10-09 11:15:55 -07001352 // Unsigned remain unchanged.
1353 case kCondB: return LO;
1354 case kCondBE: return LS;
1355 case kCondA: return HI;
1356 case kCondAE: return HS;
Dave Allison20dfc792014-06-16 20:44:29 -07001357 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001358 LOG(FATAL) << "Unreachable";
1359 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -07001360}
1361
Vladimir Markod6e069b2016-01-18 11:11:01 +00001362inline Condition ARMFPCondition(IfCondition cond, bool gt_bias) {
1363 // The ARM condition codes can express all the necessary branches, see the
1364 // "Meaning (floating-point)" column in the table A8-1 of the ARMv7 reference manual.
1365 // There is no dex instruction or HIR that would need the missing conditions
1366 // "equal or unordered" or "not equal".
1367 switch (cond) {
1368 case kCondEQ: return EQ;
1369 case kCondNE: return NE /* unordered */;
1370 case kCondLT: return gt_bias ? CC : LT /* unordered */;
1371 case kCondLE: return gt_bias ? LS : LE /* unordered */;
1372 case kCondGT: return gt_bias ? HI /* unordered */ : GT;
1373 case kCondGE: return gt_bias ? CS /* unordered */ : GE;
1374 default:
1375 LOG(FATAL) << "UNREACHABLE";
1376 UNREACHABLE();
1377 }
1378}
1379
Anton Kirilov74234da2017-01-13 14:42:47 +00001380inline Shift ShiftFromOpKind(HDataProcWithShifterOp::OpKind op_kind) {
1381 switch (op_kind) {
1382 case HDataProcWithShifterOp::kASR: return ASR;
1383 case HDataProcWithShifterOp::kLSL: return LSL;
1384 case HDataProcWithShifterOp::kLSR: return LSR;
1385 default:
1386 LOG(FATAL) << "Unexpected op kind " << op_kind;
1387 UNREACHABLE();
1388 }
1389}
1390
1391static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
1392 Register out,
1393 Register first,
1394 const ShifterOperand& second,
1395 CodeGeneratorARM* codegen) {
1396 if (second.IsImmediate() && second.GetImmediate() == 0) {
1397 const ShifterOperand in = kind == HInstruction::kAnd
1398 ? ShifterOperand(0)
1399 : ShifterOperand(first);
1400
1401 __ mov(out, in);
1402 } else {
1403 switch (kind) {
1404 case HInstruction::kAdd:
1405 __ add(out, first, second);
1406 break;
1407 case HInstruction::kAnd:
1408 __ and_(out, first, second);
1409 break;
1410 case HInstruction::kOr:
1411 __ orr(out, first, second);
1412 break;
1413 case HInstruction::kSub:
1414 __ sub(out, first, second);
1415 break;
1416 case HInstruction::kXor:
1417 __ eor(out, first, second);
1418 break;
1419 default:
1420 LOG(FATAL) << "Unexpected instruction kind: " << kind;
1421 UNREACHABLE();
1422 }
1423 }
1424}
1425
1426static void GenerateDataProc(HInstruction::InstructionKind kind,
1427 const Location& out,
1428 const Location& first,
1429 const ShifterOperand& second_lo,
1430 const ShifterOperand& second_hi,
1431 CodeGeneratorARM* codegen) {
1432 const Register first_hi = first.AsRegisterPairHigh<Register>();
1433 const Register first_lo = first.AsRegisterPairLow<Register>();
1434 const Register out_hi = out.AsRegisterPairHigh<Register>();
1435 const Register out_lo = out.AsRegisterPairLow<Register>();
1436
1437 if (kind == HInstruction::kAdd) {
1438 __ adds(out_lo, first_lo, second_lo);
1439 __ adc(out_hi, first_hi, second_hi);
1440 } else if (kind == HInstruction::kSub) {
1441 __ subs(out_lo, first_lo, second_lo);
1442 __ sbc(out_hi, first_hi, second_hi);
1443 } else {
1444 GenerateDataProcInstruction(kind, out_lo, first_lo, second_lo, codegen);
1445 GenerateDataProcInstruction(kind, out_hi, first_hi, second_hi, codegen);
1446 }
1447}
1448
1449static ShifterOperand GetShifterOperand(Register rm, Shift shift, uint32_t shift_imm) {
1450 return shift_imm == 0 ? ShifterOperand(rm) : ShifterOperand(rm, shift, shift_imm);
1451}
1452
1453static void GenerateLongDataProc(HDataProcWithShifterOp* instruction, CodeGeneratorARM* codegen) {
1454 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
1455 DCHECK(HDataProcWithShifterOp::IsShiftOp(instruction->GetOpKind()));
1456
1457 const LocationSummary* const locations = instruction->GetLocations();
1458 const uint32_t shift_value = instruction->GetShiftAmount();
1459 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
1460 const Location first = locations->InAt(0);
1461 const Location second = locations->InAt(1);
1462 const Location out = locations->Out();
1463 const Register first_hi = first.AsRegisterPairHigh<Register>();
1464 const Register first_lo = first.AsRegisterPairLow<Register>();
1465 const Register out_hi = out.AsRegisterPairHigh<Register>();
1466 const Register out_lo = out.AsRegisterPairLow<Register>();
1467 const Register second_hi = second.AsRegisterPairHigh<Register>();
1468 const Register second_lo = second.AsRegisterPairLow<Register>();
1469 const Shift shift = ShiftFromOpKind(instruction->GetOpKind());
1470
1471 if (shift_value >= 32) {
1472 if (shift == LSL) {
1473 GenerateDataProcInstruction(kind,
1474 out_hi,
1475 first_hi,
1476 ShifterOperand(second_lo, LSL, shift_value - 32),
1477 codegen);
1478 GenerateDataProcInstruction(kind,
1479 out_lo,
1480 first_lo,
1481 ShifterOperand(0),
1482 codegen);
1483 } else if (shift == ASR) {
1484 GenerateDataProc(kind,
1485 out,
1486 first,
1487 GetShifterOperand(second_hi, ASR, shift_value - 32),
1488 ShifterOperand(second_hi, ASR, 31),
1489 codegen);
1490 } else {
1491 DCHECK_EQ(shift, LSR);
1492 GenerateDataProc(kind,
1493 out,
1494 first,
1495 GetShifterOperand(second_hi, LSR, shift_value - 32),
1496 ShifterOperand(0),
1497 codegen);
1498 }
1499 } else {
1500 DCHECK_GT(shift_value, 1U);
1501 DCHECK_LT(shift_value, 32U);
1502
1503 if (shift == LSL) {
1504 // We are not doing this for HInstruction::kAdd because the output will require
1505 // Location::kOutputOverlap; not applicable to other cases.
1506 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1507 GenerateDataProcInstruction(kind,
1508 out_hi,
1509 first_hi,
1510 ShifterOperand(second_hi, LSL, shift_value),
1511 codegen);
1512 GenerateDataProcInstruction(kind,
1513 out_hi,
1514 out_hi,
1515 ShifterOperand(second_lo, LSR, 32 - shift_value),
1516 codegen);
1517 GenerateDataProcInstruction(kind,
1518 out_lo,
1519 first_lo,
1520 ShifterOperand(second_lo, LSL, shift_value),
1521 codegen);
1522 } else {
1523 __ Lsl(IP, second_hi, shift_value);
1524 __ orr(IP, IP, ShifterOperand(second_lo, LSR, 32 - shift_value));
1525 GenerateDataProc(kind,
1526 out,
1527 first,
1528 ShifterOperand(second_lo, LSL, shift_value),
1529 ShifterOperand(IP),
1530 codegen);
1531 }
1532 } else {
1533 DCHECK(shift == ASR || shift == LSR);
1534
1535 // We are not doing this for HInstruction::kAdd because the output will require
1536 // Location::kOutputOverlap; not applicable to other cases.
1537 if (kind == HInstruction::kOr || kind == HInstruction::kXor) {
1538 GenerateDataProcInstruction(kind,
1539 out_lo,
1540 first_lo,
1541 ShifterOperand(second_lo, LSR, shift_value),
1542 codegen);
1543 GenerateDataProcInstruction(kind,
1544 out_lo,
1545 out_lo,
1546 ShifterOperand(second_hi, LSL, 32 - shift_value),
1547 codegen);
1548 GenerateDataProcInstruction(kind,
1549 out_hi,
1550 first_hi,
1551 ShifterOperand(second_hi, shift, shift_value),
1552 codegen);
1553 } else {
1554 __ Lsr(IP, second_lo, shift_value);
1555 __ orr(IP, IP, ShifterOperand(second_hi, LSL, 32 - shift_value));
1556 GenerateDataProc(kind,
1557 out,
1558 first,
1559 ShifterOperand(IP),
1560 ShifterOperand(second_hi, shift, shift_value),
1561 codegen);
1562 }
1563 }
1564 }
1565}
1566
Donghui Bai426b49c2016-11-08 14:55:38 +08001567static void GenerateVcmp(HInstruction* instruction, CodeGeneratorARM* codegen) {
1568 Primitive::Type type = instruction->InputAt(0)->GetType();
1569 Location lhs_loc = instruction->GetLocations()->InAt(0);
1570 Location rhs_loc = instruction->GetLocations()->InAt(1);
1571 if (rhs_loc.IsConstant()) {
1572 // 0.0 is the only immediate that can be encoded directly in
1573 // a VCMP instruction.
1574 //
1575 // Both the JLS (section 15.20.1) and the JVMS (section 6.5)
1576 // specify that in a floating-point comparison, positive zero
1577 // and negative zero are considered equal, so we can use the
1578 // literal 0.0 for both cases here.
1579 //
1580 // Note however that some methods (Float.equal, Float.compare,
1581 // Float.compareTo, Double.equal, Double.compare,
1582 // Double.compareTo, Math.max, Math.min, StrictMath.max,
1583 // StrictMath.min) consider 0.0 to be (strictly) greater than
1584 // -0.0. So if we ever translate calls to these methods into a
1585 // HCompare instruction, we must handle the -0.0 case with
1586 // care here.
1587 DCHECK(rhs_loc.GetConstant()->IsArithmeticZero());
1588 if (type == Primitive::kPrimFloat) {
1589 __ vcmpsz(lhs_loc.AsFpuRegister<SRegister>());
1590 } else {
1591 DCHECK_EQ(type, Primitive::kPrimDouble);
1592 __ vcmpdz(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()));
1593 }
1594 } else {
1595 if (type == Primitive::kPrimFloat) {
1596 __ vcmps(lhs_loc.AsFpuRegister<SRegister>(), rhs_loc.AsFpuRegister<SRegister>());
1597 } else {
1598 DCHECK_EQ(type, Primitive::kPrimDouble);
1599 __ vcmpd(FromLowSToD(lhs_loc.AsFpuRegisterPairLow<SRegister>()),
1600 FromLowSToD(rhs_loc.AsFpuRegisterPairLow<SRegister>()));
1601 }
1602 }
1603}
1604
Anton Kirilovb404f342017-03-30 16:00:41 +01001605static int64_t AdjustConstantForCondition(int64_t value,
1606 IfCondition* condition,
1607 IfCondition* opposite) {
1608 if (value == 1) {
1609 if (*condition == kCondB) {
1610 value = 0;
1611 *condition = kCondEQ;
1612 *opposite = kCondNE;
1613 } else if (*condition == kCondAE) {
1614 value = 0;
1615 *condition = kCondNE;
1616 *opposite = kCondEQ;
1617 }
1618 } else if (value == -1) {
1619 if (*condition == kCondGT) {
1620 value = 0;
1621 *condition = kCondGE;
1622 *opposite = kCondLT;
1623 } else if (*condition == kCondLE) {
1624 value = 0;
1625 *condition = kCondLT;
1626 *opposite = kCondGE;
1627 }
1628 }
1629
1630 return value;
1631}
1632
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001633static std::pair<Condition, Condition> GenerateLongTestConstant(HCondition* condition,
1634 bool invert,
1635 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001636 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1637
1638 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001639 IfCondition cond = condition->GetCondition();
1640 IfCondition opposite = condition->GetOppositeCondition();
1641
1642 if (invert) {
1643 std::swap(cond, opposite);
1644 }
1645
Anton Kirilovb404f342017-03-30 16:00:41 +01001646 std::pair<Condition, Condition> ret(EQ, NE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001647 const Location left = locations->InAt(0);
1648 const Location right = locations->InAt(1);
1649
1650 DCHECK(right.IsConstant());
1651
1652 const Register left_high = left.AsRegisterPairHigh<Register>();
1653 const Register left_low = left.AsRegisterPairLow<Register>();
Anton Kirilovb404f342017-03-30 16:00:41 +01001654 int64_t value = AdjustConstantForCondition(right.GetConstant()->AsLongConstant()->GetValue(),
1655 &cond,
1656 &opposite);
1657
1658 // Comparisons against 0 are common enough to deserve special attention.
1659 if (value == 0) {
1660 switch (cond) {
1661 case kCondNE:
1662 // x > 0 iff x != 0 when the comparison is unsigned.
1663 case kCondA:
1664 ret = std::make_pair(NE, EQ);
1665 FALLTHROUGH_INTENDED;
1666 case kCondEQ:
1667 // x <= 0 iff x == 0 when the comparison is unsigned.
1668 case kCondBE:
1669 __ orrs(IP, left_low, ShifterOperand(left_high));
1670 return ret;
1671 case kCondLT:
1672 case kCondGE:
1673 __ cmp(left_high, ShifterOperand(0));
1674 return std::make_pair(ARMCondition(cond), ARMCondition(opposite));
1675 // Trivially true or false.
1676 case kCondB:
1677 ret = std::make_pair(NE, EQ);
1678 FALLTHROUGH_INTENDED;
1679 case kCondAE:
1680 __ cmp(left_low, ShifterOperand(left_low));
1681 return ret;
1682 default:
1683 break;
1684 }
1685 }
Donghui Bai426b49c2016-11-08 14:55:38 +08001686
1687 switch (cond) {
1688 case kCondEQ:
1689 case kCondNE:
1690 case kCondB:
1691 case kCondBE:
1692 case kCondA:
1693 case kCondAE:
1694 __ CmpConstant(left_high, High32Bits(value));
1695 __ it(EQ);
1696 __ cmp(left_low, ShifterOperand(Low32Bits(value)), EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001697 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001698 break;
1699 case kCondLE:
1700 case kCondGT:
1701 // Trivially true or false.
1702 if (value == std::numeric_limits<int64_t>::max()) {
1703 __ cmp(left_low, ShifterOperand(left_low));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001704 ret = cond == kCondLE ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
Donghui Bai426b49c2016-11-08 14:55:38 +08001705 break;
1706 }
1707
1708 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001709 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001710 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001711 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001712 } else {
1713 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001714 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001715 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001716 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001717 }
1718
1719 value++;
1720 FALLTHROUGH_INTENDED;
1721 case kCondGE:
1722 case kCondLT:
1723 __ CmpConstant(left_low, Low32Bits(value));
1724 __ sbcs(IP, left_high, ShifterOperand(High32Bits(value)));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001725 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001726 break;
1727 default:
1728 LOG(FATAL) << "Unreachable";
1729 UNREACHABLE();
1730 }
1731
1732 return ret;
1733}
1734
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001735static std::pair<Condition, Condition> GenerateLongTest(HCondition* condition,
1736 bool invert,
1737 CodeGeneratorARM* codegen) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001738 DCHECK_EQ(condition->GetLeft()->GetType(), Primitive::kPrimLong);
1739
1740 const LocationSummary* const locations = condition->GetLocations();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001741 IfCondition cond = condition->GetCondition();
1742 IfCondition opposite = condition->GetOppositeCondition();
1743
1744 if (invert) {
1745 std::swap(cond, opposite);
1746 }
1747
1748 std::pair<Condition, Condition> ret;
Donghui Bai426b49c2016-11-08 14:55:38 +08001749 Location left = locations->InAt(0);
1750 Location right = locations->InAt(1);
1751
1752 DCHECK(right.IsRegisterPair());
1753
1754 switch (cond) {
1755 case kCondEQ:
1756 case kCondNE:
1757 case kCondB:
1758 case kCondBE:
1759 case kCondA:
1760 case kCondAE:
1761 __ cmp(left.AsRegisterPairHigh<Register>(),
1762 ShifterOperand(right.AsRegisterPairHigh<Register>()));
1763 __ it(EQ);
1764 __ cmp(left.AsRegisterPairLow<Register>(),
1765 ShifterOperand(right.AsRegisterPairLow<Register>()),
1766 EQ);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001767 ret = std::make_pair(ARMUnsignedCondition(cond), ARMUnsignedCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001768 break;
1769 case kCondLE:
1770 case kCondGT:
1771 if (cond == kCondLE) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001772 DCHECK_EQ(opposite, kCondGT);
Donghui Bai426b49c2016-11-08 14:55:38 +08001773 cond = kCondGE;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001774 opposite = kCondLT;
Donghui Bai426b49c2016-11-08 14:55:38 +08001775 } else {
1776 DCHECK_EQ(cond, kCondGT);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001777 DCHECK_EQ(opposite, kCondLE);
Donghui Bai426b49c2016-11-08 14:55:38 +08001778 cond = kCondLT;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001779 opposite = kCondGE;
Donghui Bai426b49c2016-11-08 14:55:38 +08001780 }
1781
1782 std::swap(left, right);
1783 FALLTHROUGH_INTENDED;
1784 case kCondGE:
1785 case kCondLT:
1786 __ cmp(left.AsRegisterPairLow<Register>(),
1787 ShifterOperand(right.AsRegisterPairLow<Register>()));
1788 __ sbcs(IP,
1789 left.AsRegisterPairHigh<Register>(),
1790 ShifterOperand(right.AsRegisterPairHigh<Register>()));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001791 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001792 break;
1793 default:
1794 LOG(FATAL) << "Unreachable";
1795 UNREACHABLE();
1796 }
1797
1798 return ret;
1799}
1800
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001801static std::pair<Condition, Condition> GenerateTest(HCondition* condition,
1802 bool invert,
1803 CodeGeneratorARM* codegen) {
1804 const LocationSummary* const locations = condition->GetLocations();
1805 const Primitive::Type type = condition->GetLeft()->GetType();
1806 IfCondition cond = condition->GetCondition();
1807 IfCondition opposite = condition->GetOppositeCondition();
1808 std::pair<Condition, Condition> ret;
1809 const Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08001810
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001811 if (invert) {
1812 std::swap(cond, opposite);
1813 }
Donghui Bai426b49c2016-11-08 14:55:38 +08001814
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001815 if (type == Primitive::kPrimLong) {
1816 ret = locations->InAt(1).IsConstant()
1817 ? GenerateLongTestConstant(condition, invert, codegen)
1818 : GenerateLongTest(condition, invert, codegen);
1819 } else if (Primitive::IsFloatingPointType(type)) {
1820 GenerateVcmp(condition, codegen);
1821 __ vmstat();
1822 ret = std::make_pair(ARMFPCondition(cond, condition->IsGtBias()),
1823 ARMFPCondition(opposite, condition->IsGtBias()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001824 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001825 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
Donghui Bai426b49c2016-11-08 14:55:38 +08001826
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001827 const Register left = locations->InAt(0).AsRegister<Register>();
1828
1829 if (right.IsRegister()) {
1830 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001831 } else {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001832 DCHECK(right.IsConstant());
1833 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
Donghui Bai426b49c2016-11-08 14:55:38 +08001834 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001835
1836 ret = std::make_pair(ARMCondition(cond), ARMCondition(opposite));
Donghui Bai426b49c2016-11-08 14:55:38 +08001837 }
1838
1839 return ret;
1840}
1841
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001842static bool CanGenerateTest(HCondition* condition, ArmAssembler* assembler) {
1843 if (condition->GetLeft()->GetType() == Primitive::kPrimLong) {
1844 const LocationSummary* const locations = condition->GetLocations();
Donghui Bai426b49c2016-11-08 14:55:38 +08001845
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001846 if (locations->InAt(1).IsConstant()) {
Anton Kirilovb404f342017-03-30 16:00:41 +01001847 IfCondition c = condition->GetCondition();
1848 IfCondition opposite = condition->GetOppositeCondition();
1849 const int64_t value = AdjustConstantForCondition(
1850 Int64FromConstant(locations->InAt(1).GetConstant()),
1851 &c,
1852 &opposite);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001853 ShifterOperand so;
Donghui Bai426b49c2016-11-08 14:55:38 +08001854
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001855 if (c < kCondLT || c > kCondGE) {
1856 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
1857 // we check that the least significant half of the first input to be compared
1858 // is in a low register (the other half is read outside an IT block), and
1859 // the constant fits in an 8-bit unsigned integer, so that a 16-bit CMP
Anton Kirilovb404f342017-03-30 16:00:41 +01001860 // encoding can be used; 0 is always handled, no matter what registers are
1861 // used by the first input.
1862 if (value != 0 &&
1863 (!ArmAssembler::IsLowRegister(locations->InAt(0).AsRegisterPairLow<Register>()) ||
1864 !IsUint<8>(Low32Bits(value)))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08001865 return false;
1866 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00001867 } else if (c == kCondLE || c == kCondGT) {
1868 if (value < std::numeric_limits<int64_t>::max() &&
1869 !assembler->ShifterOperandCanHold(kNoRegister,
1870 kNoRegister,
1871 SBC,
1872 High32Bits(value + 1),
1873 kCcSet,
1874 &so)) {
1875 return false;
1876 }
1877 } else if (!assembler->ShifterOperandCanHold(kNoRegister,
1878 kNoRegister,
1879 SBC,
1880 High32Bits(value),
1881 kCcSet,
1882 &so)) {
1883 return false;
Donghui Bai426b49c2016-11-08 14:55:38 +08001884 }
1885 }
1886 }
1887
1888 return true;
1889}
1890
Anton Kirilovb404f342017-03-30 16:00:41 +01001891static void GenerateConditionGeneric(HCondition* cond, CodeGeneratorARM* codegen) {
1892 DCHECK(CanGenerateTest(cond, codegen->GetAssembler()));
1893
1894 const Register out = cond->GetLocations()->Out().AsRegister<Register>();
1895 const auto condition = GenerateTest(cond, false, codegen);
1896
1897 __ mov(out, ShifterOperand(0), AL, kCcKeep);
1898
1899 if (ArmAssembler::IsLowRegister(out)) {
1900 __ it(condition.first);
1901 __ mov(out, ShifterOperand(1), condition.first);
1902 } else {
1903 Label done_label;
1904 Label* const final_label = codegen->GetFinalLabel(cond, &done_label);
1905
1906 __ b(final_label, condition.second);
1907 __ LoadImmediate(out, 1);
1908
1909 if (done_label.IsLinked()) {
1910 __ Bind(&done_label);
1911 }
1912 }
1913}
1914
1915static void GenerateEqualLong(HCondition* cond, CodeGeneratorARM* codegen) {
1916 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
1917
1918 const LocationSummary* const locations = cond->GetLocations();
1919 IfCondition condition = cond->GetCondition();
1920 const Register out = locations->Out().AsRegister<Register>();
1921 const Location left = locations->InAt(0);
1922 const Location right = locations->InAt(1);
1923 Register left_high = left.AsRegisterPairHigh<Register>();
1924 Register left_low = left.AsRegisterPairLow<Register>();
1925
1926 if (right.IsConstant()) {
1927 IfCondition opposite = cond->GetOppositeCondition();
1928 const int64_t value = AdjustConstantForCondition(Int64FromConstant(right.GetConstant()),
1929 &condition,
1930 &opposite);
1931 int32_t value_high = -High32Bits(value);
1932 int32_t value_low = -Low32Bits(value);
1933
1934 // The output uses Location::kNoOutputOverlap.
1935 if (out == left_high) {
1936 std::swap(left_low, left_high);
1937 std::swap(value_low, value_high);
1938 }
1939
1940 __ AddConstant(out, left_low, value_low);
1941 __ AddConstant(IP, left_high, value_high);
1942 } else {
1943 DCHECK(right.IsRegisterPair());
1944 __ sub(IP, left_high, ShifterOperand(right.AsRegisterPairHigh<Register>()));
1945 __ sub(out, left_low, ShifterOperand(right.AsRegisterPairLow<Register>()));
1946 }
1947
1948 // Need to check after calling AdjustConstantForCondition().
1949 DCHECK(condition == kCondEQ || condition == kCondNE) << condition;
1950
1951 if (condition == kCondNE && ArmAssembler::IsLowRegister(out)) {
1952 __ orrs(out, out, ShifterOperand(IP));
1953 __ it(NE);
1954 __ mov(out, ShifterOperand(1), NE);
1955 } else {
1956 __ orr(out, out, ShifterOperand(IP));
1957 codegen->GenerateConditionWithZero(condition, out, out, IP);
1958 }
1959}
1960
1961static void GenerateLongComparesAndJumps(HCondition* cond,
1962 Label* true_label,
1963 Label* false_label,
1964 CodeGeneratorARM* codegen) {
1965 LocationSummary* locations = cond->GetLocations();
1966 Location left = locations->InAt(0);
1967 Location right = locations->InAt(1);
1968 IfCondition if_cond = cond->GetCondition();
1969
1970 Register left_high = left.AsRegisterPairHigh<Register>();
1971 Register left_low = left.AsRegisterPairLow<Register>();
1972 IfCondition true_high_cond = if_cond;
1973 IfCondition false_high_cond = cond->GetOppositeCondition();
1974 Condition final_condition = ARMUnsignedCondition(if_cond); // unsigned on lower part
1975
1976 // Set the conditions for the test, remembering that == needs to be
1977 // decided using the low words.
1978 switch (if_cond) {
1979 case kCondEQ:
1980 case kCondNE:
1981 // Nothing to do.
1982 break;
1983 case kCondLT:
1984 false_high_cond = kCondGT;
1985 break;
1986 case kCondLE:
1987 true_high_cond = kCondLT;
1988 break;
1989 case kCondGT:
1990 false_high_cond = kCondLT;
1991 break;
1992 case kCondGE:
1993 true_high_cond = kCondGT;
1994 break;
1995 case kCondB:
1996 false_high_cond = kCondA;
1997 break;
1998 case kCondBE:
1999 true_high_cond = kCondB;
2000 break;
2001 case kCondA:
2002 false_high_cond = kCondB;
2003 break;
2004 case kCondAE:
2005 true_high_cond = kCondA;
2006 break;
2007 }
2008 if (right.IsConstant()) {
2009 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
2010 int32_t val_low = Low32Bits(value);
2011 int32_t val_high = High32Bits(value);
2012
2013 __ CmpConstant(left_high, val_high);
2014 if (if_cond == kCondNE) {
2015 __ b(true_label, ARMCondition(true_high_cond));
2016 } else if (if_cond == kCondEQ) {
2017 __ b(false_label, ARMCondition(false_high_cond));
2018 } else {
2019 __ b(true_label, ARMCondition(true_high_cond));
2020 __ b(false_label, ARMCondition(false_high_cond));
2021 }
2022 // Must be equal high, so compare the lows.
2023 __ CmpConstant(left_low, val_low);
2024 } else {
2025 Register right_high = right.AsRegisterPairHigh<Register>();
2026 Register right_low = right.AsRegisterPairLow<Register>();
2027
2028 __ cmp(left_high, ShifterOperand(right_high));
2029 if (if_cond == kCondNE) {
2030 __ b(true_label, ARMCondition(true_high_cond));
2031 } else if (if_cond == kCondEQ) {
2032 __ b(false_label, ARMCondition(false_high_cond));
2033 } else {
2034 __ b(true_label, ARMCondition(true_high_cond));
2035 __ b(false_label, ARMCondition(false_high_cond));
2036 }
2037 // Must be equal high, so compare the lows.
2038 __ cmp(left_low, ShifterOperand(right_low));
2039 }
2040 // The last comparison might be unsigned.
2041 // TODO: optimize cases where this is always true/false
2042 __ b(true_label, final_condition);
2043}
2044
2045static void GenerateConditionLong(HCondition* cond, CodeGeneratorARM* codegen) {
2046 DCHECK_EQ(cond->GetLeft()->GetType(), Primitive::kPrimLong);
2047
2048 const LocationSummary* const locations = cond->GetLocations();
2049 IfCondition condition = cond->GetCondition();
2050 const Register out = locations->Out().AsRegister<Register>();
2051 const Location left = locations->InAt(0);
2052 const Location right = locations->InAt(1);
2053
2054 if (right.IsConstant()) {
2055 IfCondition opposite = cond->GetOppositeCondition();
2056
2057 // Comparisons against 0 are common enough to deserve special attention.
2058 if (AdjustConstantForCondition(Int64FromConstant(right.GetConstant()),
2059 &condition,
2060 &opposite) == 0) {
2061 switch (condition) {
2062 case kCondNE:
2063 case kCondA:
2064 if (ArmAssembler::IsLowRegister(out)) {
2065 // We only care if both input registers are 0 or not.
2066 __ orrs(out,
2067 left.AsRegisterPairLow<Register>(),
2068 ShifterOperand(left.AsRegisterPairHigh<Register>()));
2069 __ it(NE);
2070 __ mov(out, ShifterOperand(1), NE);
2071 return;
2072 }
2073
2074 FALLTHROUGH_INTENDED;
2075 case kCondEQ:
2076 case kCondBE:
2077 // We only care if both input registers are 0 or not.
2078 __ orr(out,
2079 left.AsRegisterPairLow<Register>(),
2080 ShifterOperand(left.AsRegisterPairHigh<Register>()));
2081 codegen->GenerateConditionWithZero(condition, out, out);
2082 return;
2083 case kCondLT:
2084 case kCondGE:
2085 // We only care about the sign bit.
2086 FALLTHROUGH_INTENDED;
2087 case kCondAE:
2088 case kCondB:
2089 codegen->GenerateConditionWithZero(condition, out, left.AsRegisterPairHigh<Register>());
2090 return;
2091 case kCondLE:
2092 case kCondGT:
2093 default:
2094 break;
2095 }
2096 }
2097 }
2098
2099 if ((condition == kCondEQ || condition == kCondNE) &&
2100 // If `out` is a low register, then the GenerateConditionGeneric()
2101 // function generates a shorter code sequence that is still branchless.
2102 (!ArmAssembler::IsLowRegister(out) || !CanGenerateTest(cond, codegen->GetAssembler()))) {
2103 GenerateEqualLong(cond, codegen);
2104 return;
2105 }
2106
2107 if (CanGenerateTest(cond, codegen->GetAssembler())) {
2108 GenerateConditionGeneric(cond, codegen);
2109 return;
2110 }
2111
2112 // Convert the jumps into the result.
2113 Label done_label;
2114 Label* const final_label = codegen->GetFinalLabel(cond, &done_label);
2115 Label true_label, false_label;
2116
2117 GenerateLongComparesAndJumps(cond, &true_label, &false_label, codegen);
2118
2119 // False case: result = 0.
2120 __ Bind(&false_label);
2121 __ mov(out, ShifterOperand(0));
2122 __ b(final_label);
2123
2124 // True case: result = 1.
2125 __ Bind(&true_label);
2126 __ mov(out, ShifterOperand(1));
2127
2128 if (done_label.IsLinked()) {
2129 __ Bind(&done_label);
2130 }
2131}
2132
2133static void GenerateConditionIntegralOrNonPrimitive(HCondition* cond, CodeGeneratorARM* codegen) {
2134 const Primitive::Type type = cond->GetLeft()->GetType();
2135
2136 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
2137
2138 if (type == Primitive::kPrimLong) {
2139 GenerateConditionLong(cond, codegen);
2140 return;
2141 }
2142
2143 const LocationSummary* const locations = cond->GetLocations();
2144 IfCondition condition = cond->GetCondition();
2145 Register in = locations->InAt(0).AsRegister<Register>();
2146 const Register out = locations->Out().AsRegister<Register>();
2147 const Location right = cond->GetLocations()->InAt(1);
2148 int64_t value;
2149
2150 if (right.IsConstant()) {
2151 IfCondition opposite = cond->GetOppositeCondition();
2152
2153 value = AdjustConstantForCondition(Int64FromConstant(right.GetConstant()),
2154 &condition,
2155 &opposite);
2156
2157 // Comparisons against 0 are common enough to deserve special attention.
2158 if (value == 0) {
2159 switch (condition) {
2160 case kCondNE:
2161 case kCondA:
2162 if (ArmAssembler::IsLowRegister(out) && out == in) {
2163 __ cmp(out, ShifterOperand(0));
2164 __ it(NE);
2165 __ mov(out, ShifterOperand(1), NE);
2166 return;
2167 }
2168
2169 FALLTHROUGH_INTENDED;
2170 case kCondEQ:
2171 case kCondBE:
2172 case kCondLT:
2173 case kCondGE:
2174 case kCondAE:
2175 case kCondB:
2176 codegen->GenerateConditionWithZero(condition, out, in);
2177 return;
2178 case kCondLE:
2179 case kCondGT:
2180 default:
2181 break;
2182 }
2183 }
2184 }
2185
2186 if (condition == kCondEQ || condition == kCondNE) {
2187 ShifterOperand operand;
2188
2189 if (right.IsConstant()) {
2190 operand = ShifterOperand(value);
2191 } else if (out == right.AsRegister<Register>()) {
2192 // Avoid 32-bit instructions if possible.
2193 operand = ShifterOperand(in);
2194 in = right.AsRegister<Register>();
2195 } else {
2196 operand = ShifterOperand(right.AsRegister<Register>());
2197 }
2198
2199 if (condition == kCondNE && ArmAssembler::IsLowRegister(out)) {
2200 __ subs(out, in, operand);
2201 __ it(NE);
2202 __ mov(out, ShifterOperand(1), NE);
2203 } else {
2204 __ sub(out, in, operand);
2205 codegen->GenerateConditionWithZero(condition, out, out);
2206 }
2207
2208 return;
2209 }
2210
2211 GenerateConditionGeneric(cond, codegen);
2212}
2213
Donghui Bai426b49c2016-11-08 14:55:38 +08002214static bool CanEncodeConstantAs8BitImmediate(HConstant* constant) {
2215 const Primitive::Type type = constant->GetType();
2216 bool ret = false;
2217
2218 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
2219
2220 if (type == Primitive::kPrimLong) {
2221 const uint64_t value = constant->AsLongConstant()->GetValueAsUint64();
2222
2223 ret = IsUint<8>(Low32Bits(value)) && IsUint<8>(High32Bits(value));
2224 } else {
2225 ret = IsUint<8>(CodeGenerator::GetInt32ValueOf(constant));
2226 }
2227
2228 return ret;
2229}
2230
2231static Location Arm8BitEncodableConstantOrRegister(HInstruction* constant) {
2232 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
2233
2234 if (constant->IsConstant() && CanEncodeConstantAs8BitImmediate(constant->AsConstant())) {
2235 return Location::ConstantLocation(constant->AsConstant());
2236 }
2237
2238 return Location::RequiresRegister();
2239}
2240
2241static bool CanGenerateConditionalMove(const Location& out, const Location& src) {
2242 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
2243 // we check that we are not dealing with floating-point output (there is no
2244 // 16-bit VMOV encoding).
2245 if (!out.IsRegister() && !out.IsRegisterPair()) {
2246 return false;
2247 }
2248
2249 // For constants, we also check that the output is in one or two low registers,
2250 // and that the constants fit in an 8-bit unsigned integer, so that a 16-bit
2251 // MOV encoding can be used.
2252 if (src.IsConstant()) {
2253 if (!CanEncodeConstantAs8BitImmediate(src.GetConstant())) {
2254 return false;
2255 }
2256
2257 if (out.IsRegister()) {
2258 if (!ArmAssembler::IsLowRegister(out.AsRegister<Register>())) {
2259 return false;
2260 }
2261 } else {
2262 DCHECK(out.IsRegisterPair());
2263
2264 if (!ArmAssembler::IsLowRegister(out.AsRegisterPairHigh<Register>())) {
2265 return false;
2266 }
2267 }
2268 }
2269
2270 return true;
2271}
2272
Anton Kirilov74234da2017-01-13 14:42:47 +00002273#undef __
2274// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
2275#define __ down_cast<ArmAssembler*>(GetAssembler())-> // NOLINT
2276
Donghui Bai426b49c2016-11-08 14:55:38 +08002277Label* CodeGeneratorARM::GetFinalLabel(HInstruction* instruction, Label* final_label) {
2278 DCHECK(!instruction->IsControlFlow() && !instruction->IsSuspendCheck());
Anton Kirilov6f644202017-02-27 18:29:45 +00002279 DCHECK(!instruction->IsInvoke() || !instruction->GetLocations()->CanCall());
Donghui Bai426b49c2016-11-08 14:55:38 +08002280
2281 const HBasicBlock* const block = instruction->GetBlock();
2282 const HLoopInformation* const info = block->GetLoopInformation();
2283 HInstruction* const next = instruction->GetNext();
2284
2285 // Avoid a branch to a branch.
2286 if (next->IsGoto() && (info == nullptr ||
2287 !info->IsBackEdge(*block) ||
2288 !info->HasSuspendCheck())) {
2289 final_label = GetLabelOf(next->AsGoto()->GetSuccessor());
2290 }
2291
2292 return final_label;
2293}
2294
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01002295void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01002296 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01002297}
2298
2299void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +01002300 stream << SRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +01002301}
2302
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002303size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
2304 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
2305 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01002306}
2307
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01002308size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
2309 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
2310 return kArmWordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +01002311}
2312
Nicolas Geoffray840e5462015-01-07 16:01:24 +00002313size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
2314 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index);
2315 return kArmWordSize;
2316}
2317
2318size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
2319 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index);
2320 return kArmWordSize;
2321}
2322
Calin Juravle34166012014-12-19 17:22:29 +00002323CodeGeneratorARM::CodeGeneratorARM(HGraph* graph,
Calin Juravlecd6dffe2015-01-08 17:35:35 +00002324 const ArmInstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +01002325 const CompilerOptions& compiler_options,
2326 OptimizingCompilerStats* stats)
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002327 : CodeGenerator(graph,
2328 kNumberOfCoreRegisters,
2329 kNumberOfSRegisters,
2330 kNumberOfRegisterPairs,
2331 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
2332 arraysize(kCoreCalleeSaves)),
Nicolas Geoffray75d5b9b2015-10-05 07:40:35 +00002333 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
2334 arraysize(kFpuCalleeSaves)),
Serban Constantinescuecc43662015-08-13 13:33:12 +01002335 compiler_options,
2336 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +01002337 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002338 location_builder_(graph, this),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002339 instruction_visitor_(graph, this),
Nicolas Geoffray8d486732014-07-16 16:23:40 +01002340 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +01002341 assembler_(graph->GetArena()),
Vladimir Marko58155012015-08-19 12:49:41 +00002342 isa_features_(isa_features),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00002343 uint32_literals_(std::less<uint32_t>(),
2344 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markocac5a7e2016-02-22 10:39:50 +00002345 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2346 boot_image_string_patches_(StringReferenceValueComparator(),
2347 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2348 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01002349 boot_image_type_patches_(TypeReferenceValueComparator(),
2350 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2351 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +00002352 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Nicolas Geoffray132d8362016-11-16 09:19:42 +00002353 jit_string_patches_(StringReferenceValueComparator(),
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00002354 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
2355 jit_class_patches_(TypeReferenceValueComparator(),
2356 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Andreas Gampe501fd632015-09-10 16:11:06 -07002357 // Always save the LR register to mimic Quick.
2358 AddAllocatedRegister(Location::RegisterLocation(LR));
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +01002359}
2360
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002361void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
2362 // Ensure that we fix up branches and literal loads and emit the literal pool.
2363 __ FinalizeCode();
2364
2365 // Adjust native pc offsets in stack maps.
2366 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08002367 uint32_t old_position =
2368 stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kThumb2);
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002369 uint32_t new_position = __ GetAdjustedPosition(old_position);
2370 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
2371 }
Alexandre Rameseb7b7392015-06-19 14:47:01 +01002372 // Adjust pc offsets for the disassembly information.
2373 if (disasm_info_ != nullptr) {
2374 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
2375 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
2376 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
2377 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
2378 it.second.start = __ GetAdjustedPosition(it.second.start);
2379 it.second.end = __ GetAdjustedPosition(it.second.end);
2380 }
2381 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
2382 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
2383 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
2384 }
2385 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +00002386
2387 CodeGenerator::Finalize(allocator);
2388}
2389
David Brazdil58282f42016-01-14 12:45:10 +00002390void CodeGeneratorARM::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002391 // Stack register, LR and PC are always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002392 blocked_core_registers_[SP] = true;
2393 blocked_core_registers_[LR] = true;
2394 blocked_core_registers_[PC] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002395
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002396 // Reserve thread register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002397 blocked_core_registers_[TR] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002398
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002399 // Reserve temp register.
Nicolas Geoffray71175b72014-10-09 22:13:55 +01002400 blocked_core_registers_[IP] = true;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002401
David Brazdil58282f42016-01-14 12:45:10 +00002402 if (GetGraph()->IsDebuggable()) {
Nicolas Geoffrayecf680d2015-10-05 11:15:37 +01002403 // Stubs do not save callee-save floating point registers. If the graph
2404 // is debuggable, we need to deal with these registers differently. For
2405 // now, just block them.
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002406 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
2407 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
2408 }
2409 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002410}
2411
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002412InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08002413 : InstructionCodeGenerator(graph, codegen),
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01002414 assembler_(codegen->GetAssembler()),
2415 codegen_(codegen) {}
2416
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002417void CodeGeneratorARM::ComputeSpillMask() {
2418 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
2419 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
David Brazdil58282f42016-01-14 12:45:10 +00002420 // There is no easy instruction to restore just the PC on thumb2. We spill and
2421 // restore another arbitrary register.
2422 core_spill_mask_ |= (1 << kCoreAlwaysSpillRegister);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002423 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
2424 // We use vpush and vpop for saving and restoring floating point registers, which take
2425 // a SRegister and the number of registers to save/restore after that SRegister. We
2426 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated,
2427 // but in the range.
2428 if (fpu_spill_mask_ != 0) {
2429 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_);
2430 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_);
2431 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) {
2432 fpu_spill_mask_ |= (1 << i);
2433 }
2434 }
2435}
2436
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002437static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002438 return dwarf::Reg::ArmCore(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002439}
2440
2441static dwarf::Reg DWARFReg(SRegister reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +01002442 return dwarf::Reg::ArmFp(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002443}
2444
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002445void CodeGeneratorARM::GenerateFrameEntry() {
Roland Levillain199f3362014-11-27 17:15:16 +00002446 bool skip_overflow_check =
2447 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002448 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00002449 __ Bind(&frame_entry_label_);
2450
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002451 if (HasEmptyFrame()) {
2452 return;
2453 }
2454
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002455 if (!skip_overflow_check) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +00002456 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
2457 __ LoadFromOffset(kLoadWord, IP, IP, 0);
2458 RecordPcInfo(nullptr, 0);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002459 }
2460
Andreas Gampe501fd632015-09-10 16:11:06 -07002461 __ PushList(core_spill_mask_);
2462 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(core_spill_mask_));
2463 __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, core_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002464 if (fpu_spill_mask_ != 0) {
2465 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2466 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002467 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_));
David Srbecky9d8606d2015-04-12 09:35:32 +01002468 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002469 }
Mingyao Yang063fc772016-08-02 11:02:54 -07002470
2471 if (GetGraph()->HasShouldDeoptimizeFlag()) {
2472 // Initialize should_deoptimize flag to 0.
2473 __ mov(IP, ShifterOperand(0));
2474 __ StoreToOffset(kStoreWord, IP, SP, -kShouldDeoptimizeFlagSize);
2475 }
2476
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002477 int adjust = GetFrameSize() - FrameEntrySpillSize();
2478 __ AddConstant(SP, -adjust);
2479 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01002480
2481 // Save the current method if we need it. Note that we do not
2482 // do this in HCurrentMethod, as the instruction might have been removed
2483 // in the SSA graph.
2484 if (RequiresCurrentMethod()) {
2485 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
2486 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002487}
2488
2489void CodeGeneratorARM::GenerateFrameExit() {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +00002490 if (HasEmptyFrame()) {
2491 __ bx(LR);
2492 return;
2493 }
David Srbeckyc34dc932015-04-12 09:27:43 +01002494 __ cfi().RememberState();
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002495 int adjust = GetFrameSize() - FrameEntrySpillSize();
2496 __ AddConstant(SP, adjust);
2497 __ cfi().AdjustCFAOffset(-adjust);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002498 if (fpu_spill_mask_ != 0) {
2499 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
2500 __ vpops(start_register, POPCOUNT(fpu_spill_mask_));
Andreas Gampe542451c2016-07-26 09:02:02 -07002501 __ cfi().AdjustCFAOffset(-static_cast<int>(kArmPointerSize) * POPCOUNT(fpu_spill_mask_));
David Srbeckyc6b4dd82015-04-07 20:32:43 +01002502 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_);
Nicolas Geoffray4dee6362015-01-23 18:23:14 +00002503 }
Andreas Gampe501fd632015-09-10 16:11:06 -07002504 // Pop LR into PC to return.
2505 DCHECK_NE(core_spill_mask_ & (1 << LR), 0U);
2506 uint32_t pop_mask = (core_spill_mask_ & (~(1 << LR))) | 1 << PC;
2507 __ PopList(pop_mask);
David Srbeckyc34dc932015-04-12 09:27:43 +01002508 __ cfi().RestoreState();
2509 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002510}
2511
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01002512void CodeGeneratorARM::Bind(HBasicBlock* block) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07002513 Label* label = GetLabelOf(block);
2514 __ BindTrackedLabel(label);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002515}
2516
Roland Levillain2d27c8e2015-04-28 15:48:45 +01002517Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002518 switch (type) {
2519 case Primitive::kPrimBoolean:
2520 case Primitive::kPrimByte:
2521 case Primitive::kPrimChar:
2522 case Primitive::kPrimShort:
2523 case Primitive::kPrimInt:
2524 case Primitive::kPrimNot: {
2525 uint32_t index = gp_index_++;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002526 uint32_t stack_index = stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002527 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002528 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002529 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002530 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002531 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002532 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002533
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002534 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002535 uint32_t index = gp_index_;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002536 uint32_t stack_index = stack_index_;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002537 gp_index_ += 2;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002538 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002539 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002540 if (calling_convention.GetRegisterAt(index) == R1) {
2541 // Skip R1, and use R2_R3 instead.
2542 gp_index_++;
2543 index++;
2544 }
2545 }
2546 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
2547 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1,
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002548 calling_convention.GetRegisterAt(index + 1));
Calin Juravle175dc732015-08-25 15:42:32 +01002549
Nicolas Geoffray69c15d32015-01-13 11:42:13 +00002550 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index),
Nicolas Geoffrayaf2c65c2015-01-14 09:40:32 +00002551 calling_convention.GetRegisterAt(index + 1));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002552 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002553 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
2554 }
2555 }
2556
2557 case Primitive::kPrimFloat: {
2558 uint32_t stack_index = stack_index_++;
2559 if (float_index_ % 2 == 0) {
2560 float_index_ = std::max(double_index_, float_index_);
2561 }
2562 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) {
2563 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++));
2564 } else {
2565 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index));
2566 }
2567 }
2568
2569 case Primitive::kPrimDouble: {
2570 double_index_ = std::max(double_index_, RoundUp(float_index_, 2));
2571 uint32_t stack_index = stack_index_;
2572 stack_index_ += 2;
2573 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) {
2574 uint32_t index = double_index_;
2575 double_index_ += 2;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002576 Location result = Location::FpuRegisterPairLocation(
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002577 calling_convention.GetFpuRegisterAt(index),
2578 calling_convention.GetFpuRegisterAt(index + 1));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002579 DCHECK(ExpectedPairLayout(result));
2580 return result;
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002581 } else {
2582 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002583 }
2584 }
2585
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002586 case Primitive::kPrimVoid:
2587 LOG(FATAL) << "Unexpected parameter type " << type;
2588 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002589 }
Roland Levillain3b359c72015-11-17 19:35:12 +00002590 return Location::NoLocation();
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002591}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01002592
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002593Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002594 switch (type) {
2595 case Primitive::kPrimBoolean:
2596 case Primitive::kPrimByte:
2597 case Primitive::kPrimChar:
2598 case Primitive::kPrimShort:
2599 case Primitive::kPrimInt:
2600 case Primitive::kPrimNot: {
2601 return Location::RegisterLocation(R0);
2602 }
2603
2604 case Primitive::kPrimFloat: {
2605 return Location::FpuRegisterLocation(S0);
2606 }
2607
2608 case Primitive::kPrimLong: {
2609 return Location::RegisterPairLocation(R0, R1);
2610 }
2611
2612 case Primitive::kPrimDouble: {
2613 return Location::FpuRegisterPairLocation(S0, S1);
2614 }
2615
2616 case Primitive::kPrimVoid:
Roland Levillain3b359c72015-11-17 19:35:12 +00002617 return Location::NoLocation();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002618 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +01002619
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002620 UNREACHABLE();
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002621}
2622
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01002623Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
2624 return Location::RegisterLocation(kMethodRegisterArgument);
2625}
2626
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002627void CodeGeneratorARM::Move32(Location destination, Location source) {
2628 if (source.Equals(destination)) {
2629 return;
2630 }
2631 if (destination.IsRegister()) {
2632 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002633 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002634 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002635 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002636 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002637 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002638 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002639 } else if (destination.IsFpuRegister()) {
2640 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002641 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002642 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002643 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002644 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002645 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002646 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002647 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002648 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002649 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002650 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002651 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002652 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002653 } else {
Calin Juravlea21f5982014-11-13 15:53:04 +00002654 DCHECK(source.IsStackSlot()) << source;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002655 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
2656 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002657 }
2658 }
2659}
2660
2661void CodeGeneratorARM::Move64(Location destination, Location source) {
2662 if (source.Equals(destination)) {
2663 return;
2664 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002665 if (destination.IsRegisterPair()) {
2666 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002667 EmitParallelMoves(
2668 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
2669 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002670 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002671 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002672 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
2673 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002674 } else if (source.IsFpuRegister()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002675 UNIMPLEMENTED(FATAL);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002676 } else if (source.IsFpuRegisterPair()) {
2677 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
2678 destination.AsRegisterPairHigh<Register>(),
2679 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002680 } else {
2681 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00002682 DCHECK(ExpectedPairLayout(destination));
2683 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(),
2684 SP, source.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002685 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002686 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002687 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002688 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2689 SP,
2690 source.GetStackIndex());
Calin Juravlee460d1d2015-09-29 04:52:17 +01002691 } else if (source.IsRegisterPair()) {
2692 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
2693 source.AsRegisterPairLow<Register>(),
2694 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002695 } else {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002696 UNIMPLEMENTED(FATAL);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002697 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002698 } else {
2699 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002700 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002701 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002702 if (source.AsRegisterPairLow<Register>() == R1) {
2703 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2);
Nicolas Geoffray360231a2014-10-08 21:07:48 +01002704 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex());
2705 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002706 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002707 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002708 SP, destination.GetStackIndex());
2709 }
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00002710 } else if (source.IsFpuRegisterPair()) {
2711 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
2712 SP,
2713 destination.GetStackIndex());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002714 } else {
2715 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002716 EmitParallelMoves(
2717 Location::StackSlot(source.GetStackIndex()),
2718 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002719 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +00002720 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +01002721 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)),
2722 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002723 }
2724 }
2725}
2726
Calin Juravle175dc732015-08-25 15:42:32 +01002727void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
2728 DCHECK(location.IsRegister());
2729 __ LoadImmediate(location.AsRegister<Register>(), value);
2730}
2731
Calin Juravlee460d1d2015-09-29 04:52:17 +01002732void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
David Brazdil74eb1b22015-12-14 11:44:01 +00002733 HParallelMove move(GetGraph()->GetArena());
2734 move.AddMove(src, dst, dst_type, nullptr);
2735 GetMoveResolver()->EmitNativeCode(&move);
Calin Juravlee460d1d2015-09-29 04:52:17 +01002736}
2737
2738void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
2739 if (location.IsRegister()) {
2740 locations->AddTemp(location);
2741 } else if (location.IsRegisterPair()) {
2742 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
2743 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
2744 } else {
2745 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
2746 }
2747}
2748
Calin Juravle175dc732015-08-25 15:42:32 +01002749void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint,
2750 HInstruction* instruction,
2751 uint32_t dex_pc,
2752 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01002753 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002754 GenerateInvokeRuntime(GetThreadOffset<kArmPointerSize>(entrypoint).Int32Value());
Serban Constantinescuda8ffec2016-03-09 12:02:11 +00002755 if (EntrypointRequiresStackMap(entrypoint)) {
2756 RecordPcInfo(instruction, dex_pc, slow_path);
2757 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002758}
2759
Roland Levillaindec8f632016-07-22 17:10:06 +01002760void CodeGeneratorARM::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
2761 HInstruction* instruction,
2762 SlowPathCode* slow_path) {
2763 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01002764 GenerateInvokeRuntime(entry_point_offset);
2765}
2766
2767void CodeGeneratorARM::GenerateInvokeRuntime(int32_t entry_point_offset) {
Roland Levillaindec8f632016-07-22 17:10:06 +01002768 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset);
2769 __ blx(LR);
2770}
2771
David Brazdilfc6a86a2015-06-26 10:33:45 +00002772void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002773 DCHECK(!successor->IsExitBlock());
2774
2775 HBasicBlock* block = got->GetBlock();
2776 HInstruction* previous = got->GetPrevious();
2777
2778 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00002779 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002780 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2781 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2782 return;
2783 }
2784
2785 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2786 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2787 }
2788 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002789 __ b(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002790 }
2791}
2792
David Brazdilfc6a86a2015-06-26 10:33:45 +00002793void LocationsBuilderARM::VisitGoto(HGoto* got) {
2794 got->SetLocations(nullptr);
2795}
2796
2797void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
2798 HandleGoto(got, got->GetSuccessor());
2799}
2800
2801void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2802 try_boundary->SetLocations(nullptr);
2803}
2804
2805void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
2806 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2807 if (!successor->IsExitBlock()) {
2808 HandleGoto(try_boundary, successor);
2809 }
2810}
2811
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002812void LocationsBuilderARM::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00002813 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002814}
2815
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01002816void InstructionCodeGeneratorARM::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002817}
2818
David Brazdil0debae72015-11-12 18:37:00 +00002819void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HCondition* condition,
2820 Label* true_target_in,
2821 Label* false_target_in) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002822 if (CanGenerateTest(condition, codegen_->GetAssembler())) {
2823 Label* non_fallthrough_target;
2824 bool invert;
2825
2826 if (true_target_in == nullptr) {
2827 DCHECK(false_target_in != nullptr);
2828 non_fallthrough_target = false_target_in;
2829 invert = true;
2830 } else {
2831 non_fallthrough_target = true_target_in;
2832 invert = false;
2833 }
2834
2835 const auto cond = GenerateTest(condition, invert, codegen_);
2836
2837 __ b(non_fallthrough_target, cond.first);
2838
2839 if (false_target_in != nullptr && false_target_in != non_fallthrough_target) {
2840 __ b(false_target_in);
2841 }
2842
2843 return;
2844 }
2845
David Brazdil0debae72015-11-12 18:37:00 +00002846 // Generated branching requires both targets to be explicit. If either of the
2847 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
2848 Label fallthrough_target;
2849 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
2850 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
2851
Anton Kirilov217b2ce2017-03-16 11:47:12 +00002852 DCHECK_EQ(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
Anton Kirilovb404f342017-03-30 16:00:41 +01002853 GenerateLongComparesAndJumps(condition, true_target, false_target, codegen_);
Roland Levillain4fa13f62015-07-06 18:11:54 +01002854
David Brazdil0debae72015-11-12 18:37:00 +00002855 if (false_target != &fallthrough_target) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01002856 __ b(false_target);
2857 }
David Brazdil0debae72015-11-12 18:37:00 +00002858
2859 if (fallthrough_target.IsLinked()) {
2860 __ Bind(&fallthrough_target);
2861 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01002862}
2863
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002864void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00002865 size_t condition_input_index,
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002866 Label* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00002867 Label* false_target) {
2868 HInstruction* cond = instruction->InputAt(condition_input_index);
2869
2870 if (true_target == nullptr && false_target == nullptr) {
2871 // Nothing to do. The code always falls through.
2872 return;
2873 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00002874 // Constant condition, statically compared against "true" (integer value 1).
2875 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00002876 if (true_target != nullptr) {
2877 __ b(true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002878 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002879 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00002880 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00002881 if (false_target != nullptr) {
2882 __ b(false_target);
2883 }
2884 }
2885 return;
2886 }
2887
2888 // The following code generates these patterns:
2889 // (1) true_target == nullptr && false_target != nullptr
2890 // - opposite condition true => branch to false_target
2891 // (2) true_target != nullptr && false_target == nullptr
2892 // - condition true => branch to true_target
2893 // (3) true_target != nullptr && false_target != nullptr
2894 // - condition true => branch to true_target
2895 // - branch to false_target
2896 if (IsBooleanValueOrMaterializedCondition(cond)) {
2897 // Condition has been materialized, compare the output to 0.
2898 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
2899 DCHECK(cond_val.IsRegister());
2900 if (true_target == nullptr) {
2901 __ CompareAndBranchIfZero(cond_val.AsRegister<Register>(), false_target);
2902 } else {
2903 __ CompareAndBranchIfNonZero(cond_val.AsRegister<Register>(), true_target);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002904 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002905 } else {
David Brazdil0debae72015-11-12 18:37:00 +00002906 // Condition has not been materialized. Use its inputs as the comparison and
2907 // its condition as the branch condition.
Mark Mendellb8b97692015-05-22 16:58:19 -04002908 HCondition* condition = cond->AsCondition();
David Brazdil0debae72015-11-12 18:37:00 +00002909
2910 // If this is a long or FP comparison that has been folded into
2911 // the HCondition, generate the comparison directly.
2912 Primitive::Type type = condition->InputAt(0)->GetType();
2913 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
2914 GenerateCompareTestAndBranch(condition, true_target, false_target);
2915 return;
2916 }
2917
Donghui Bai426b49c2016-11-08 14:55:38 +08002918 Label* non_fallthrough_target;
2919 Condition arm_cond;
David Brazdil0debae72015-11-12 18:37:00 +00002920 LocationSummary* locations = cond->GetLocations();
2921 DCHECK(locations->InAt(0).IsRegister());
2922 Register left = locations->InAt(0).AsRegister<Register>();
2923 Location right = locations->InAt(1);
Donghui Bai426b49c2016-11-08 14:55:38 +08002924
David Brazdil0debae72015-11-12 18:37:00 +00002925 if (true_target == nullptr) {
Donghui Bai426b49c2016-11-08 14:55:38 +08002926 arm_cond = ARMCondition(condition->GetOppositeCondition());
2927 non_fallthrough_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00002928 } else {
Donghui Bai426b49c2016-11-08 14:55:38 +08002929 arm_cond = ARMCondition(condition->GetCondition());
2930 non_fallthrough_target = true_target;
2931 }
2932
2933 if (right.IsConstant() && (arm_cond == NE || arm_cond == EQ) &&
2934 CodeGenerator::GetInt32ValueOf(right.GetConstant()) == 0) {
2935 if (arm_cond == EQ) {
2936 __ CompareAndBranchIfZero(left, non_fallthrough_target);
2937 } else {
2938 DCHECK_EQ(arm_cond, NE);
2939 __ CompareAndBranchIfNonZero(left, non_fallthrough_target);
2940 }
2941 } else {
2942 if (right.IsRegister()) {
2943 __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
2944 } else {
2945 DCHECK(right.IsConstant());
2946 __ CmpConstant(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
2947 }
2948
2949 __ b(non_fallthrough_target, arm_cond);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01002950 }
Dave Allison20dfc792014-06-16 20:44:29 -07002951 }
David Brazdil0debae72015-11-12 18:37:00 +00002952
2953 // If neither branch falls through (case 3), the conditional branch to `true_target`
2954 // was already emitted (case 2) and we need to emit a jump to `false_target`.
2955 if (true_target != nullptr && false_target != nullptr) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002956 __ b(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00002957 }
2958}
2959
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002960void LocationsBuilderARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00002961 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
2962 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002963 locations->SetInAt(0, Location::RequiresRegister());
2964 }
2965}
2966
2967void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00002968 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
2969 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
2970 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
2971 nullptr : codegen_->GetLabelOf(true_successor);
2972 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
2973 nullptr : codegen_->GetLabelOf(false_successor);
2974 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002975}
2976
2977void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
2978 LocationSummary* locations = new (GetGraph()->GetArena())
2979 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01002980 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
David Brazdil0debae72015-11-12 18:37:00 +00002981 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002982 locations->SetInAt(0, Location::RequiresRegister());
2983 }
2984}
2985
2986void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01002987 SlowPathCodeARM* slow_path = deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathARM>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00002988 GenerateTestAndBranch(deoptimize,
2989 /* condition_input_index */ 0,
2990 slow_path->GetEntryLabel(),
2991 /* false_target */ nullptr);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07002992}
Dave Allison20dfc792014-06-16 20:44:29 -07002993
Mingyao Yang063fc772016-08-02 11:02:54 -07002994void LocationsBuilderARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
2995 LocationSummary* locations = new (GetGraph()->GetArena())
2996 LocationSummary(flag, LocationSummary::kNoCall);
2997 locations->SetOut(Location::RequiresRegister());
2998}
2999
3000void InstructionCodeGeneratorARM::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
3001 __ LoadFromOffset(kLoadWord,
3002 flag->GetLocations()->Out().AsRegister<Register>(),
3003 SP,
3004 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
3005}
3006
David Brazdil74eb1b22015-12-14 11:44:01 +00003007void LocationsBuilderARM::VisitSelect(HSelect* select) {
3008 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
Donghui Bai426b49c2016-11-08 14:55:38 +08003009 const bool is_floating_point = Primitive::IsFloatingPointType(select->GetType());
3010
3011 if (is_floating_point) {
David Brazdil74eb1b22015-12-14 11:44:01 +00003012 locations->SetInAt(0, Location::RequiresFpuRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08003013 locations->SetInAt(1, Location::FpuRegisterOrConstant(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00003014 } else {
3015 locations->SetInAt(0, Location::RequiresRegister());
Donghui Bai426b49c2016-11-08 14:55:38 +08003016 locations->SetInAt(1, Arm8BitEncodableConstantOrRegister(select->GetTrueValue()));
David Brazdil74eb1b22015-12-14 11:44:01 +00003017 }
Donghui Bai426b49c2016-11-08 14:55:38 +08003018
David Brazdil74eb1b22015-12-14 11:44:01 +00003019 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
Donghui Bai426b49c2016-11-08 14:55:38 +08003020 locations->SetInAt(2, Location::RegisterOrConstant(select->GetCondition()));
3021 // The code generator handles overlap with the values, but not with the condition.
3022 locations->SetOut(Location::SameAsFirstInput());
3023 } else if (is_floating_point) {
3024 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3025 } else {
3026 if (!locations->InAt(1).IsConstant()) {
3027 locations->SetInAt(0, Arm8BitEncodableConstantOrRegister(select->GetFalseValue()));
3028 }
3029
3030 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
David Brazdil74eb1b22015-12-14 11:44:01 +00003031 }
David Brazdil74eb1b22015-12-14 11:44:01 +00003032}
3033
3034void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
Donghui Bai426b49c2016-11-08 14:55:38 +08003035 HInstruction* const condition = select->GetCondition();
3036 const LocationSummary* const locations = select->GetLocations();
3037 const Primitive::Type type = select->GetType();
3038 const Location first = locations->InAt(0);
3039 const Location out = locations->Out();
3040 const Location second = locations->InAt(1);
3041 Location src;
3042
3043 if (condition->IsIntConstant()) {
3044 if (condition->AsIntConstant()->IsFalse()) {
3045 src = first;
3046 } else {
3047 src = second;
3048 }
3049
3050 codegen_->MoveLocation(out, src, type);
3051 return;
3052 }
3053
3054 if (!Primitive::IsFloatingPointType(type) &&
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003055 (IsBooleanValueOrMaterializedCondition(condition) ||
3056 CanGenerateTest(condition->AsCondition(), codegen_->GetAssembler()))) {
Donghui Bai426b49c2016-11-08 14:55:38 +08003057 bool invert = false;
3058
3059 if (out.Equals(second)) {
3060 src = first;
3061 invert = true;
3062 } else if (out.Equals(first)) {
3063 src = second;
3064 } else if (second.IsConstant()) {
3065 DCHECK(CanEncodeConstantAs8BitImmediate(second.GetConstant()));
3066 src = second;
3067 } else if (first.IsConstant()) {
3068 DCHECK(CanEncodeConstantAs8BitImmediate(first.GetConstant()));
3069 src = first;
3070 invert = true;
3071 } else {
3072 src = second;
3073 }
3074
3075 if (CanGenerateConditionalMove(out, src)) {
3076 if (!out.Equals(first) && !out.Equals(second)) {
3077 codegen_->MoveLocation(out, src.Equals(first) ? second : first, type);
3078 }
3079
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003080 std::pair<Condition, Condition> cond;
3081
3082 if (IsBooleanValueOrMaterializedCondition(condition)) {
3083 __ CmpConstant(locations->InAt(2).AsRegister<Register>(), 0);
3084 cond = invert ? std::make_pair(EQ, NE) : std::make_pair(NE, EQ);
3085 } else {
3086 cond = GenerateTest(condition->AsCondition(), invert, codegen_);
3087 }
Donghui Bai426b49c2016-11-08 14:55:38 +08003088
3089 if (out.IsRegister()) {
3090 ShifterOperand operand;
3091
3092 if (src.IsConstant()) {
3093 operand = ShifterOperand(CodeGenerator::GetInt32ValueOf(src.GetConstant()));
3094 } else {
3095 DCHECK(src.IsRegister());
3096 operand = ShifterOperand(src.AsRegister<Register>());
3097 }
3098
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003099 __ it(cond.first);
3100 __ mov(out.AsRegister<Register>(), operand, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08003101 } else {
3102 DCHECK(out.IsRegisterPair());
3103
3104 ShifterOperand operand_high;
3105 ShifterOperand operand_low;
3106
3107 if (src.IsConstant()) {
3108 const int64_t value = src.GetConstant()->AsLongConstant()->GetValue();
3109
3110 operand_high = ShifterOperand(High32Bits(value));
3111 operand_low = ShifterOperand(Low32Bits(value));
3112 } else {
3113 DCHECK(src.IsRegisterPair());
3114 operand_high = ShifterOperand(src.AsRegisterPairHigh<Register>());
3115 operand_low = ShifterOperand(src.AsRegisterPairLow<Register>());
3116 }
3117
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003118 __ it(cond.first);
3119 __ mov(out.AsRegisterPairLow<Register>(), operand_low, cond.first);
3120 __ it(cond.first);
3121 __ mov(out.AsRegisterPairHigh<Register>(), operand_high, cond.first);
Donghui Bai426b49c2016-11-08 14:55:38 +08003122 }
3123
3124 return;
3125 }
3126 }
3127
3128 Label* false_target = nullptr;
3129 Label* true_target = nullptr;
3130 Label select_end;
3131 Label* target = codegen_->GetFinalLabel(select, &select_end);
3132
3133 if (out.Equals(second)) {
3134 true_target = target;
3135 src = first;
3136 } else {
3137 false_target = target;
3138 src = second;
3139
3140 if (!out.Equals(first)) {
3141 codegen_->MoveLocation(out, first, type);
3142 }
3143 }
3144
3145 GenerateTestAndBranch(select, 2, true_target, false_target);
3146 codegen_->MoveLocation(out, src, type);
3147
3148 if (select_end.IsLinked()) {
3149 __ Bind(&select_end);
3150 }
David Brazdil74eb1b22015-12-14 11:44:01 +00003151}
3152
David Srbecky0cf44932015-12-09 14:09:59 +00003153void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
3154 new (GetGraph()->GetArena()) LocationSummary(info);
3155}
3156
David Srbeckyd28f4a02016-03-14 17:14:24 +00003157void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo*) {
3158 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00003159}
3160
3161void CodeGeneratorARM::GenerateNop() {
3162 __ nop();
David Srbecky0cf44932015-12-09 14:09:59 +00003163}
3164
Anton Kirilovb404f342017-03-30 16:00:41 +01003165// `temp` is an extra temporary register that is used for some conditions;
3166// callers may not specify it, in which case the method will use a scratch
3167// register instead.
3168void CodeGeneratorARM::GenerateConditionWithZero(IfCondition condition,
3169 Register out,
3170 Register in,
3171 Register temp) {
3172 switch (condition) {
3173 case kCondEQ:
3174 // x <= 0 iff x == 0 when the comparison is unsigned.
3175 case kCondBE:
3176 if (temp == kNoRegister || (ArmAssembler::IsLowRegister(out) && out != in)) {
3177 temp = out;
3178 }
3179
3180 // Avoid 32-bit instructions if possible; note that `in` and `temp` must be
3181 // different as well.
3182 if (ArmAssembler::IsLowRegister(in) && ArmAssembler::IsLowRegister(temp) && in != temp) {
3183 // temp = - in; only 0 sets the carry flag.
3184 __ rsbs(temp, in, ShifterOperand(0));
3185
3186 if (out == in) {
3187 std::swap(in, temp);
3188 }
3189
3190 // out = - in + in + carry = carry
3191 __ adc(out, temp, ShifterOperand(in));
3192 } else {
3193 // If `in` is 0, then it has 32 leading zeros, and less than that otherwise.
3194 __ clz(out, in);
3195 // Any number less than 32 logically shifted right by 5 bits results in 0;
3196 // the same operation on 32 yields 1.
3197 __ Lsr(out, out, 5);
3198 }
3199
3200 break;
3201 case kCondNE:
3202 // x > 0 iff x != 0 when the comparison is unsigned.
3203 case kCondA:
3204 if (out == in) {
3205 if (temp == kNoRegister || in == temp) {
3206 temp = IP;
3207 }
3208 } else if (temp == kNoRegister || !ArmAssembler::IsLowRegister(temp)) {
3209 temp = out;
3210 }
3211
3212 // temp = in - 1; only 0 does not set the carry flag.
3213 __ subs(temp, in, ShifterOperand(1));
3214 // out = in + ~temp + carry = in + (-(in - 1) - 1) + carry = in - in + 1 - 1 + carry = carry
3215 __ sbc(out, in, ShifterOperand(temp));
3216 break;
3217 case kCondGE:
3218 __ mvn(out, ShifterOperand(in));
3219 in = out;
3220 FALLTHROUGH_INTENDED;
3221 case kCondLT:
3222 // We only care about the sign bit.
3223 __ Lsr(out, in, 31);
3224 break;
3225 case kCondAE:
3226 // Trivially true.
3227 __ mov(out, ShifterOperand(1));
3228 break;
3229 case kCondB:
3230 // Trivially false.
3231 __ mov(out, ShifterOperand(0));
3232 break;
3233 default:
3234 LOG(FATAL) << "Unexpected condition " << condition;
3235 UNREACHABLE();
3236 }
3237}
3238
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003239void LocationsBuilderARM::HandleCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003240 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01003241 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003242 // Handle the long/FP comparisons made in instruction simplification.
3243 switch (cond->InputAt(0)->GetType()) {
3244 case Primitive::kPrimLong:
3245 locations->SetInAt(0, Location::RequiresRegister());
3246 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00003247 if (!cond->IsEmittedAtUseSite()) {
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003248 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003249 }
3250 break;
3251
3252 case Primitive::kPrimFloat:
3253 case Primitive::kPrimDouble:
3254 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01003255 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00003256 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01003257 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3258 }
3259 break;
3260
3261 default:
3262 locations->SetInAt(0, Location::RequiresRegister());
3263 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
David Brazdilb3e773e2016-01-26 11:28:37 +00003264 if (!cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01003265 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3266 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003267 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003268}
3269
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003270void InstructionCodeGeneratorARM::HandleCondition(HCondition* cond) {
David Brazdilb3e773e2016-01-26 11:28:37 +00003271 if (cond->IsEmittedAtUseSite()) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01003272 return;
Dave Allison20dfc792014-06-16 20:44:29 -07003273 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01003274
Anton Kirilovb404f342017-03-30 16:00:41 +01003275 const Primitive::Type type = cond->GetLeft()->GetType();
Roland Levillain4fa13f62015-07-06 18:11:54 +01003276
Anton Kirilovb404f342017-03-30 16:00:41 +01003277 if (Primitive::IsFloatingPointType(type)) {
3278 GenerateConditionGeneric(cond, codegen_);
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003279 return;
Roland Levillain4fa13f62015-07-06 18:11:54 +01003280 }
3281
Anton Kirilovb404f342017-03-30 16:00:41 +01003282 DCHECK(Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) << type;
Roland Levillain4fa13f62015-07-06 18:11:54 +01003283
Anton Kirilovb404f342017-03-30 16:00:41 +01003284 if (type == Primitive::kPrimBoolean) {
3285 const LocationSummary* const locations = cond->GetLocations();
3286 const IfCondition c = cond->GetCondition();
3287 Register left = locations->InAt(0).AsRegister<Register>();
3288 const Register out = locations->Out().AsRegister<Register>();
3289 const Location right_loc = locations->InAt(1);
Roland Levillain4fa13f62015-07-06 18:11:54 +01003290
Anton Kirilovb404f342017-03-30 16:00:41 +01003291 // All other cases are handled by the instruction simplifier.
3292 DCHECK((c == kCondEQ || c == kCondNE) && !right_loc.IsConstant());
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003293
Anton Kirilovb404f342017-03-30 16:00:41 +01003294 Register right = right_loc.AsRegister<Register>();
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003295
Anton Kirilovb404f342017-03-30 16:00:41 +01003296 // Avoid 32-bit instructions if possible.
3297 if (out == right) {
3298 std::swap(left, right);
3299 }
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003300
Anton Kirilovb404f342017-03-30 16:00:41 +01003301 __ eor(out, left, ShifterOperand(right));
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003302
Anton Kirilovb404f342017-03-30 16:00:41 +01003303 if (c == kCondEQ) {
3304 __ eor(out, out, ShifterOperand(1));
3305 }
3306
3307 return;
Anton Kirilov217b2ce2017-03-16 11:47:12 +00003308 }
Anton Kirilov6f644202017-02-27 18:29:45 +00003309
Anton Kirilovb404f342017-03-30 16:00:41 +01003310 GenerateConditionIntegralOrNonPrimitive(cond, codegen_);
Dave Allison20dfc792014-06-16 20:44:29 -07003311}
3312
3313void LocationsBuilderARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003314 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003315}
3316
3317void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003318 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003319}
3320
3321void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003322 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003323}
3324
3325void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003326 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003327}
3328
3329void LocationsBuilderARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003330 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003331}
3332
3333void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003334 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003335}
3336
3337void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003338 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003339}
3340
3341void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003342 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003343}
3344
3345void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003346 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003347}
3348
3349void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003350 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003351}
3352
3353void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003354 HandleCondition(comp);
Dave Allison20dfc792014-06-16 20:44:29 -07003355}
3356
3357void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003358 HandleCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003359}
3360
Aart Bike9f37602015-10-09 11:15:55 -07003361void LocationsBuilderARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003362 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003363}
3364
3365void InstructionCodeGeneratorARM::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003366 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003367}
3368
3369void LocationsBuilderARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003370 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003371}
3372
3373void InstructionCodeGeneratorARM::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003374 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003375}
3376
3377void LocationsBuilderARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003378 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003379}
3380
3381void InstructionCodeGeneratorARM::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003382 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003383}
3384
3385void LocationsBuilderARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003386 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003387}
3388
3389void InstructionCodeGeneratorARM::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003390 HandleCondition(comp);
Aart Bike9f37602015-10-09 11:15:55 -07003391}
3392
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003393void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003394 LocationSummary* locations =
3395 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003396 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003397}
3398
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003399void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01003400 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003401}
3402
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003403void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
3404 LocationSummary* locations =
3405 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3406 locations->SetOut(Location::ConstantLocation(constant));
3407}
3408
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003409void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003410 // Will be generated at use site.
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003411}
3412
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003413void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003414 LocationSummary* locations =
3415 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003416 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003417}
3418
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003419void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01003420 // Will be generated at use site.
3421}
3422
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003423void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
3424 LocationSummary* locations =
3425 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3426 locations->SetOut(Location::ConstantLocation(constant));
3427}
3428
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003429void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003430 // Will be generated at use site.
3431}
3432
3433void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
3434 LocationSummary* locations =
3435 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
3436 locations->SetOut(Location::ConstantLocation(constant));
3437}
3438
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003439void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) {
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01003440 // Will be generated at use site.
3441}
3442
Calin Juravle27df7582015-04-17 19:12:31 +01003443void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
3444 memory_barrier->SetLocations(nullptr);
3445}
3446
3447void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00003448 codegen_->GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
Calin Juravle27df7582015-04-17 19:12:31 +01003449}
3450
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003451void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003452 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00003453}
3454
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003455void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003456 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003457}
3458
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003459void LocationsBuilderARM::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003460 LocationSummary* locations =
3461 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00003462 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003463}
3464
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01003465void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00003466 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00003467}
3468
Calin Juravle175dc732015-08-25 15:42:32 +01003469void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3470 // The trampoline uses the same calling convention as dex calling conventions,
3471 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
3472 // the method_idx.
3473 HandleInvoke(invoke);
3474}
3475
3476void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
3477 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
3478}
3479
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003480void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003481 // Explicit clinit checks triggered by static invokes must have been pruned by
3482 // art::PrepareForRegisterAllocation.
3483 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003484
Vladimir Marko68c981f2016-08-26 13:13:33 +01003485 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003486 if (intrinsic.TryDispatch(invoke)) {
Vladimir Markob4536b72015-11-24 13:45:23 +00003487 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
3488 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
3489 }
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003490 return;
3491 }
3492
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003493 HandleInvoke(invoke);
Vladimir Markob4536b72015-11-24 13:45:23 +00003494
3495 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
3496 if (invoke->HasPcRelativeDexCache()) {
3497 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
3498 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003499}
3500
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003501static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
3502 if (invoke->GetLocations()->Intrinsified()) {
3503 IntrinsicCodeGeneratorARM intrinsic(codegen);
3504 intrinsic.Dispatch(invoke);
3505 return true;
3506 }
3507 return false;
3508}
3509
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00003510void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003511 // Explicit clinit checks triggered by static invokes must have been pruned by
3512 // art::PrepareForRegisterAllocation.
3513 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01003514
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003515 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3516 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00003517 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003518
Nicolas Geoffray38207af2015-06-01 15:46:22 +01003519 LocationSummary* locations = invoke->GetLocations();
3520 codegen_->GenerateStaticOrDirectCall(
3521 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +00003522 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003523}
3524
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003525void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01003526 InvokeDexCallingConventionVisitorARM calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01003527 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003528}
3529
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003530void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Vladimir Marko68c981f2016-08-26 13:13:33 +01003531 IntrinsicLocationsBuilderARM intrinsic(codegen_);
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003532 if (intrinsic.TryDispatch(invoke)) {
3533 return;
3534 }
3535
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003536 HandleInvoke(invoke);
3537}
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003538
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003539void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08003540 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3541 return;
3542 }
3543
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003544 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003545 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01003546 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00003547}
3548
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003549void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3550 HandleInvoke(invoke);
3551 // Add the hidden argument.
3552 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12));
3553}
3554
3555void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) {
3556 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain3b359c72015-11-17 19:35:12 +00003557 LocationSummary* locations = invoke->GetLocations();
3558 Register temp = locations->GetTemp(0).AsRegister<Register>();
3559 Register hidden_reg = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003560 Location receiver = locations->InAt(0);
3561 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3562
Roland Levillain3b359c72015-11-17 19:35:12 +00003563 // Set the hidden argument. This is safe to do this here, as R12
3564 // won't be modified thereafter, before the `blx` (call) instruction.
3565 DCHECK_EQ(R12, hidden_reg);
3566 __ LoadImmediate(hidden_reg, invoke->GetDexMethodIndex());
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003567
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003568 if (receiver.IsStackSlot()) {
3569 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
Roland Levillain3b359c72015-11-17 19:35:12 +00003570 // /* HeapReference<Class> */ temp = temp->klass_
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003571 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
3572 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00003573 // /* HeapReference<Class> */ temp = receiver->klass_
Roland Levillain271ab9c2014-11-27 15:23:57 +00003574 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003575 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003576 codegen_->MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00003577 // Instead of simply (possibly) unpoisoning `temp` here, we should
3578 // emit a read barrier for the previous class reference load.
3579 // However this is not required in practice, as this is an
3580 // intermediate/temporary reference and because the current
3581 // concurrent copying collector keeps the from-space memory
3582 // intact/accessible until the end of the marking phase (the
3583 // concurrent copying collector may not in the future).
Roland Levillain4d027112015-07-01 15:41:14 +01003584 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003585 __ LoadFromOffset(kLoadWord, temp, temp,
3586 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
3587 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00003588 invoke->GetImtIndex(), kArmPointerSize));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003589 // temp = temp->GetImtEntryAt(method_offset);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00003590 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00003591 uint32_t entry_point =
Andreas Gampe542451c2016-07-26 09:02:02 -07003592 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00003593 // LR = temp->GetEntryPoint();
3594 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
3595 // LR();
3596 __ blx(LR);
3597 DCHECK(!codegen_->IsLeafMethod());
3598 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3599}
3600
Orion Hodsonac141392017-01-13 11:53:47 +00003601void LocationsBuilderARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3602 HandleInvoke(invoke);
3603}
3604
3605void InstructionCodeGeneratorARM::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
3606 codegen_->GenerateInvokePolymorphicCall(invoke);
3607}
3608
Roland Levillain88cb1752014-10-20 16:36:47 +01003609void LocationsBuilderARM::VisitNeg(HNeg* neg) {
3610 LocationSummary* locations =
3611 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
3612 switch (neg->GetResultType()) {
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003613 case Primitive::kPrimInt: {
Roland Levillain88cb1752014-10-20 16:36:47 +01003614 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00003615 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3616 break;
3617 }
3618 case Primitive::kPrimLong: {
3619 locations->SetInAt(0, Location::RequiresRegister());
3620 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003621 break;
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003622 }
Roland Levillain88cb1752014-10-20 16:36:47 +01003623
Roland Levillain88cb1752014-10-20 16:36:47 +01003624 case Primitive::kPrimFloat:
3625 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003626 locations->SetInAt(0, Location::RequiresFpuRegister());
3627 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillain88cb1752014-10-20 16:36:47 +01003628 break;
3629
3630 default:
3631 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3632 }
3633}
3634
3635void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
3636 LocationSummary* locations = neg->GetLocations();
3637 Location out = locations->Out();
3638 Location in = locations->InAt(0);
3639 switch (neg->GetResultType()) {
3640 case Primitive::kPrimInt:
3641 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003642 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0));
Roland Levillain88cb1752014-10-20 16:36:47 +01003643 break;
3644
3645 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01003646 DCHECK(in.IsRegisterPair());
3647 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag)
3648 __ rsbs(out.AsRegisterPairLow<Register>(),
3649 in.AsRegisterPairLow<Register>(),
3650 ShifterOperand(0));
3651 // We cannot emit an RSC (Reverse Subtract with Carry)
3652 // instruction here, as it does not exist in the Thumb-2
3653 // instruction set. We use the following approach
3654 // using SBC and SUB instead.
3655 //
3656 // out.hi = -C
3657 __ sbc(out.AsRegisterPairHigh<Register>(),
3658 out.AsRegisterPairHigh<Register>(),
3659 ShifterOperand(out.AsRegisterPairHigh<Register>()));
3660 // out.hi = out.hi - in.hi
3661 __ sub(out.AsRegisterPairHigh<Register>(),
3662 out.AsRegisterPairHigh<Register>(),
3663 ShifterOperand(in.AsRegisterPairHigh<Register>()));
3664 break;
3665
Roland Levillain88cb1752014-10-20 16:36:47 +01003666 case Primitive::kPrimFloat:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003667 DCHECK(in.IsFpuRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003668 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
Roland Levillain3dbcb382014-10-28 17:30:07 +00003669 break;
3670
Roland Levillain88cb1752014-10-20 16:36:47 +01003671 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00003672 DCHECK(in.IsFpuRegisterPair());
3673 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
3674 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain88cb1752014-10-20 16:36:47 +01003675 break;
3676
3677 default:
3678 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
3679 }
3680}
3681
Roland Levillaindff1f282014-11-05 14:15:05 +00003682void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00003683 Primitive::Type result_type = conversion->GetResultType();
3684 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003685 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00003686
Roland Levillain5b3ee562015-04-14 16:02:41 +01003687 // The float-to-long, double-to-long and long-to-float type conversions
3688 // rely on a call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00003689 LocationSummary::CallKind call_kind =
Roland Levillain5b3ee562015-04-14 16:02:41 +01003690 (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
3691 && result_type == Primitive::kPrimLong)
3692 || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003693 ? LocationSummary::kCallOnMainOnly
Roland Levillain624279f2014-12-04 11:54:28 +00003694 : LocationSummary::kNoCall;
3695 LocationSummary* locations =
3696 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
3697
David Brazdilb2bd1c52015-03-25 11:17:37 +00003698 // The Java language does not allow treating boolean as an integral type but
3699 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00003700
Roland Levillaindff1f282014-11-05 14:15:05 +00003701 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003702 case Primitive::kPrimByte:
3703 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003704 case Primitive::kPrimLong:
3705 // Type conversion from long to byte is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003706 case Primitive::kPrimBoolean:
3707 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003708 case Primitive::kPrimShort:
3709 case Primitive::kPrimInt:
3710 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003711 // Processing a Dex `int-to-byte' instruction.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003712 locations->SetInAt(0, Location::RequiresRegister());
3713 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3714 break;
3715
3716 default:
3717 LOG(FATAL) << "Unexpected type conversion from " << input_type
3718 << " to " << result_type;
3719 }
3720 break;
3721
Roland Levillain01a8d712014-11-14 16:27:39 +00003722 case Primitive::kPrimShort:
3723 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003724 case Primitive::kPrimLong:
3725 // Type conversion from long to short is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003726 case Primitive::kPrimBoolean:
3727 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00003728 case Primitive::kPrimByte:
3729 case Primitive::kPrimInt:
3730 case Primitive::kPrimChar:
3731 // Processing a Dex `int-to-short' instruction.
3732 locations->SetInAt(0, Location::RequiresRegister());
3733 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3734 break;
3735
3736 default:
3737 LOG(FATAL) << "Unexpected type conversion from " << input_type
3738 << " to " << result_type;
3739 }
3740 break;
3741
Roland Levillain946e1432014-11-11 17:35:19 +00003742 case Primitive::kPrimInt:
3743 switch (input_type) {
3744 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00003745 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00003746 locations->SetInAt(0, Location::Any());
3747 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3748 break;
3749
3750 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00003751 // Processing a Dex `float-to-int' instruction.
3752 locations->SetInAt(0, Location::RequiresFpuRegister());
3753 locations->SetOut(Location::RequiresRegister());
3754 locations->AddTemp(Location::RequiresFpuRegister());
3755 break;
3756
Roland Levillain946e1432014-11-11 17:35:19 +00003757 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003758 // Processing a Dex `double-to-int' instruction.
3759 locations->SetInAt(0, Location::RequiresFpuRegister());
3760 locations->SetOut(Location::RequiresRegister());
3761 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00003762 break;
3763
3764 default:
3765 LOG(FATAL) << "Unexpected type conversion from " << input_type
3766 << " to " << result_type;
3767 }
3768 break;
3769
Roland Levillaindff1f282014-11-05 14:15:05 +00003770 case Primitive::kPrimLong:
3771 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003772 case Primitive::kPrimBoolean:
3773 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00003774 case Primitive::kPrimByte:
3775 case Primitive::kPrimShort:
3776 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00003777 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003778 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00003779 locations->SetInAt(0, Location::RequiresRegister());
3780 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3781 break;
3782
Roland Levillain624279f2014-12-04 11:54:28 +00003783 case Primitive::kPrimFloat: {
3784 // Processing a Dex `float-to-long' instruction.
3785 InvokeRuntimeCallingConvention calling_convention;
3786 locations->SetInAt(0, Location::FpuRegisterLocation(
3787 calling_convention.GetFpuRegisterAt(0)));
3788 locations->SetOut(Location::RegisterPairLocation(R0, R1));
3789 break;
3790 }
3791
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003792 case Primitive::kPrimDouble: {
3793 // Processing a Dex `double-to-long' instruction.
3794 InvokeRuntimeCallingConvention calling_convention;
3795 locations->SetInAt(0, Location::FpuRegisterPairLocation(
3796 calling_convention.GetFpuRegisterAt(0),
3797 calling_convention.GetFpuRegisterAt(1)));
3798 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Roland Levillaindff1f282014-11-05 14:15:05 +00003799 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003800 }
Roland Levillaindff1f282014-11-05 14:15:05 +00003801
3802 default:
3803 LOG(FATAL) << "Unexpected type conversion from " << input_type
3804 << " to " << result_type;
3805 }
3806 break;
3807
Roland Levillain981e4542014-11-14 11:47:14 +00003808 case Primitive::kPrimChar:
3809 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003810 case Primitive::kPrimLong:
3811 // Type conversion from long to char is a result of code transformations.
David Brazdil46e2a392015-03-16 17:31:52 +00003812 case Primitive::kPrimBoolean:
3813 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00003814 case Primitive::kPrimByte:
3815 case Primitive::kPrimShort:
3816 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00003817 // Processing a Dex `int-to-char' instruction.
3818 locations->SetInAt(0, Location::RequiresRegister());
3819 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3820 break;
3821
3822 default:
3823 LOG(FATAL) << "Unexpected type conversion from " << input_type
3824 << " to " << result_type;
3825 }
3826 break;
3827
Roland Levillaindff1f282014-11-05 14:15:05 +00003828 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00003829 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003830 case Primitive::kPrimBoolean:
3831 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003832 case Primitive::kPrimByte:
3833 case Primitive::kPrimShort:
3834 case Primitive::kPrimInt:
3835 case Primitive::kPrimChar:
3836 // Processing a Dex `int-to-float' instruction.
3837 locations->SetInAt(0, Location::RequiresRegister());
3838 locations->SetOut(Location::RequiresFpuRegister());
3839 break;
3840
Roland Levillain5b3ee562015-04-14 16:02:41 +01003841 case Primitive::kPrimLong: {
Roland Levillain6d0e4832014-11-27 18:31:21 +00003842 // Processing a Dex `long-to-float' instruction.
Roland Levillain5b3ee562015-04-14 16:02:41 +01003843 InvokeRuntimeCallingConvention calling_convention;
3844 locations->SetInAt(0, Location::RegisterPairLocation(
3845 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3846 locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
Roland Levillain6d0e4832014-11-27 18:31:21 +00003847 break;
Roland Levillain5b3ee562015-04-14 16:02:41 +01003848 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00003849
Roland Levillaincff13742014-11-17 14:32:17 +00003850 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003851 // Processing a Dex `double-to-float' instruction.
3852 locations->SetInAt(0, Location::RequiresFpuRegister());
3853 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003854 break;
3855
3856 default:
3857 LOG(FATAL) << "Unexpected type conversion from " << input_type
3858 << " to " << result_type;
3859 };
3860 break;
3861
Roland Levillaindff1f282014-11-05 14:15:05 +00003862 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00003863 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003864 case Primitive::kPrimBoolean:
3865 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00003866 case Primitive::kPrimByte:
3867 case Primitive::kPrimShort:
3868 case Primitive::kPrimInt:
3869 case Primitive::kPrimChar:
3870 // Processing a Dex `int-to-double' instruction.
3871 locations->SetInAt(0, Location::RequiresRegister());
3872 locations->SetOut(Location::RequiresFpuRegister());
3873 break;
3874
3875 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00003876 // Processing a Dex `long-to-double' instruction.
3877 locations->SetInAt(0, Location::RequiresRegister());
3878 locations->SetOut(Location::RequiresFpuRegister());
Roland Levillain682393c2015-04-14 15:57:52 +01003879 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain647b9ed2014-11-27 12:06:00 +00003880 locations->AddTemp(Location::RequiresFpuRegister());
3881 break;
3882
Roland Levillaincff13742014-11-17 14:32:17 +00003883 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00003884 // Processing a Dex `float-to-double' instruction.
3885 locations->SetInAt(0, Location::RequiresFpuRegister());
3886 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00003887 break;
3888
3889 default:
3890 LOG(FATAL) << "Unexpected type conversion from " << input_type
3891 << " to " << result_type;
3892 };
Roland Levillaindff1f282014-11-05 14:15:05 +00003893 break;
3894
3895 default:
3896 LOG(FATAL) << "Unexpected type conversion from " << input_type
3897 << " to " << result_type;
3898 }
3899}
3900
3901void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
3902 LocationSummary* locations = conversion->GetLocations();
3903 Location out = locations->Out();
3904 Location in = locations->InAt(0);
3905 Primitive::Type result_type = conversion->GetResultType();
3906 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00003907 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00003908 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00003909 case Primitive::kPrimByte:
3910 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003911 case Primitive::kPrimLong:
3912 // Type conversion from long to byte is a result of code transformations.
3913 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
3914 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003915 case Primitive::kPrimBoolean:
3916 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00003917 case Primitive::kPrimShort:
3918 case Primitive::kPrimInt:
3919 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003920 // Processing a Dex `int-to-byte' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003921 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8);
Roland Levillain51d3fc42014-11-13 14:11:42 +00003922 break;
3923
3924 default:
3925 LOG(FATAL) << "Unexpected type conversion from " << input_type
3926 << " to " << result_type;
3927 }
3928 break;
3929
Roland Levillain01a8d712014-11-14 16:27:39 +00003930 case Primitive::kPrimShort:
3931 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00003932 case Primitive::kPrimLong:
3933 // Type conversion from long to short is a result of code transformations.
3934 __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
3935 break;
David Brazdil46e2a392015-03-16 17:31:52 +00003936 case Primitive::kPrimBoolean:
3937 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00003938 case Primitive::kPrimByte:
3939 case Primitive::kPrimInt:
3940 case Primitive::kPrimChar:
3941 // Processing a Dex `int-to-short' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00003942 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain01a8d712014-11-14 16:27:39 +00003943 break;
3944
3945 default:
3946 LOG(FATAL) << "Unexpected type conversion from " << input_type
3947 << " to " << result_type;
3948 }
3949 break;
3950
Roland Levillain946e1432014-11-11 17:35:19 +00003951 case Primitive::kPrimInt:
3952 switch (input_type) {
3953 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00003954 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00003955 DCHECK(out.IsRegister());
3956 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003957 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00003958 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003959 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex());
Roland Levillain946e1432014-11-11 17:35:19 +00003960 } else {
3961 DCHECK(in.IsConstant());
3962 DCHECK(in.GetConstant()->IsLongConstant());
3963 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003964 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value));
Roland Levillain946e1432014-11-11 17:35:19 +00003965 }
3966 break;
3967
Roland Levillain3f8f9362014-12-02 17:45:01 +00003968 case Primitive::kPrimFloat: {
3969 // Processing a Dex `float-to-int' instruction.
3970 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01003971 __ vcvtis(temp, in.AsFpuRegister<SRegister>());
Roland Levillain3f8f9362014-12-02 17:45:01 +00003972 __ vmovrs(out.AsRegister<Register>(), temp);
3973 break;
3974 }
3975
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003976 case Primitive::kPrimDouble: {
3977 // Processing a Dex `double-to-int' instruction.
3978 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Vladimir Marko8c5d3102016-07-07 12:07:44 +01003979 __ vcvtid(temp_s, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003980 __ vmovrs(out.AsRegister<Register>(), temp_s);
Roland Levillain946e1432014-11-11 17:35:19 +00003981 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00003982 }
Roland Levillain946e1432014-11-11 17:35:19 +00003983
3984 default:
3985 LOG(FATAL) << "Unexpected type conversion from " << input_type
3986 << " to " << result_type;
3987 }
3988 break;
3989
Roland Levillaindff1f282014-11-05 14:15:05 +00003990 case Primitive::kPrimLong:
3991 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00003992 case Primitive::kPrimBoolean:
3993 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00003994 case Primitive::kPrimByte:
3995 case Primitive::kPrimShort:
3996 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00003997 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00003998 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00003999 DCHECK(out.IsRegisterPair());
4000 DCHECK(in.IsRegister());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004001 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>());
Roland Levillaindff1f282014-11-05 14:15:05 +00004002 // Sign extension.
4003 __ Asr(out.AsRegisterPairHigh<Register>(),
4004 out.AsRegisterPairLow<Register>(),
4005 31);
4006 break;
4007
4008 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00004009 // Processing a Dex `float-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004010 codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004011 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
Roland Levillain624279f2014-12-04 11:54:28 +00004012 break;
4013
Roland Levillaindff1f282014-11-05 14:15:05 +00004014 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00004015 // Processing a Dex `double-to-long' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004016 codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004017 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
Roland Levillaindff1f282014-11-05 14:15:05 +00004018 break;
4019
4020 default:
4021 LOG(FATAL) << "Unexpected type conversion from " << input_type
4022 << " to " << result_type;
4023 }
4024 break;
4025
Roland Levillain981e4542014-11-14 11:47:14 +00004026 case Primitive::kPrimChar:
4027 switch (input_type) {
Vladimir Markob52bbde2016-02-12 12:06:05 +00004028 case Primitive::kPrimLong:
4029 // Type conversion from long to char is a result of code transformations.
4030 __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
4031 break;
David Brazdil46e2a392015-03-16 17:31:52 +00004032 case Primitive::kPrimBoolean:
4033 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00004034 case Primitive::kPrimByte:
4035 case Primitive::kPrimShort:
4036 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00004037 // Processing a Dex `int-to-char' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004038 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16);
Roland Levillain981e4542014-11-14 11:47:14 +00004039 break;
4040
4041 default:
4042 LOG(FATAL) << "Unexpected type conversion from " << input_type
4043 << " to " << result_type;
4044 }
4045 break;
4046
Roland Levillaindff1f282014-11-05 14:15:05 +00004047 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00004048 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00004049 case Primitive::kPrimBoolean:
4050 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00004051 case Primitive::kPrimByte:
4052 case Primitive::kPrimShort:
4053 case Primitive::kPrimInt:
4054 case Primitive::kPrimChar: {
4055 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004056 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>());
4057 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00004058 break;
4059 }
4060
Roland Levillain5b3ee562015-04-14 16:02:41 +01004061 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00004062 // Processing a Dex `long-to-float' instruction.
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004063 codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004064 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
Roland Levillain6d0e4832014-11-27 18:31:21 +00004065 break;
Roland Levillain6d0e4832014-11-27 18:31:21 +00004066
Roland Levillaincff13742014-11-17 14:32:17 +00004067 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00004068 // Processing a Dex `double-to-float' instruction.
4069 __ vcvtsd(out.AsFpuRegister<SRegister>(),
4070 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
Roland Levillaincff13742014-11-17 14:32:17 +00004071 break;
4072
4073 default:
4074 LOG(FATAL) << "Unexpected type conversion from " << input_type
4075 << " to " << result_type;
4076 };
4077 break;
4078
Roland Levillaindff1f282014-11-05 14:15:05 +00004079 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00004080 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00004081 case Primitive::kPrimBoolean:
4082 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00004083 case Primitive::kPrimByte:
4084 case Primitive::kPrimShort:
4085 case Primitive::kPrimInt:
4086 case Primitive::kPrimChar: {
4087 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00004088 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00004089 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4090 out.AsFpuRegisterPairLow<SRegister>());
4091 break;
4092 }
4093
Roland Levillain647b9ed2014-11-27 12:06:00 +00004094 case Primitive::kPrimLong: {
4095 // Processing a Dex `long-to-double' instruction.
4096 Register low = in.AsRegisterPairLow<Register>();
4097 Register high = in.AsRegisterPairHigh<Register>();
4098 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
4099 DRegister out_d = FromLowSToD(out_s);
Roland Levillain682393c2015-04-14 15:57:52 +01004100 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00004101 DRegister temp_d = FromLowSToD(temp_s);
Roland Levillain682393c2015-04-14 15:57:52 +01004102 SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
4103 DRegister constant_d = FromLowSToD(constant_s);
Roland Levillain647b9ed2014-11-27 12:06:00 +00004104
Roland Levillain682393c2015-04-14 15:57:52 +01004105 // temp_d = int-to-double(high)
4106 __ vmovsr(temp_s, high);
4107 __ vcvtdi(temp_d, temp_s);
4108 // constant_d = k2Pow32EncodingForDouble
4109 __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
4110 // out_d = unsigned-to-double(low)
4111 __ vmovsr(out_s, low);
4112 __ vcvtdu(out_d, out_s);
4113 // out_d += temp_d * constant_d
4114 __ vmlad(out_d, temp_d, constant_d);
Roland Levillain647b9ed2014-11-27 12:06:00 +00004115 break;
4116 }
4117
Roland Levillaincff13742014-11-17 14:32:17 +00004118 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00004119 // Processing a Dex `float-to-double' instruction.
4120 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4121 in.AsFpuRegister<SRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00004122 break;
4123
4124 default:
4125 LOG(FATAL) << "Unexpected type conversion from " << input_type
4126 << " to " << result_type;
4127 };
Roland Levillaindff1f282014-11-05 14:15:05 +00004128 break;
4129
4130 default:
4131 LOG(FATAL) << "Unexpected type conversion from " << input_type
4132 << " to " << result_type;
4133 }
4134}
4135
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004136void LocationsBuilderARM::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004137 LocationSummary* locations =
4138 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004139 switch (add->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004140 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004141 locations->SetInAt(0, Location::RequiresRegister());
4142 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004143 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4144 break;
4145 }
4146
4147 case Primitive::kPrimLong: {
4148 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01004149 locations->SetInAt(1, ArmEncodableConstantOrRegister(add->InputAt(1), ADD));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004150 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004151 break;
4152 }
4153
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004154 case Primitive::kPrimFloat:
4155 case Primitive::kPrimDouble: {
4156 locations->SetInAt(0, Location::RequiresFpuRegister());
4157 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004158 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004159 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004160 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004161
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004162 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004163 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004164 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004165}
4166
4167void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) {
4168 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004169 Location out = locations->Out();
4170 Location first = locations->InAt(0);
4171 Location second = locations->InAt(1);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004172 switch (add->GetResultType()) {
4173 case Primitive::kPrimInt:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004174 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004175 __ add(out.AsRegister<Register>(),
4176 first.AsRegister<Register>(),
4177 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004178 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004179 __ AddConstant(out.AsRegister<Register>(),
4180 first.AsRegister<Register>(),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004181 second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004182 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004183 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004184
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004185 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01004186 if (second.IsConstant()) {
4187 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
4188 GenerateAddLongConst(out, first, value);
4189 } else {
4190 DCHECK(second.IsRegisterPair());
4191 __ adds(out.AsRegisterPairLow<Register>(),
4192 first.AsRegisterPairLow<Register>(),
4193 ShifterOperand(second.AsRegisterPairLow<Register>()));
4194 __ adc(out.AsRegisterPairHigh<Register>(),
4195 first.AsRegisterPairHigh<Register>(),
4196 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4197 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004198 break;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004199 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004200
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004201 case Primitive::kPrimFloat:
Roland Levillain199f3362014-11-27 17:15:16 +00004202 __ vadds(out.AsFpuRegister<SRegister>(),
4203 first.AsFpuRegister<SRegister>(),
4204 second.AsFpuRegister<SRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004205 break;
4206
4207 case Primitive::kPrimDouble:
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004208 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4209 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4210 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004211 break;
4212
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004213 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01004214 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00004215 }
4216}
4217
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004218void LocationsBuilderARM::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004219 LocationSummary* locations =
4220 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004221 switch (sub->GetResultType()) {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004222 case Primitive::kPrimInt: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004223 locations->SetInAt(0, Location::RequiresRegister());
4224 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004225 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4226 break;
4227 }
4228
4229 case Primitive::kPrimLong: {
4230 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko59751a72016-08-05 14:37:27 +01004231 locations->SetInAt(1, ArmEncodableConstantOrRegister(sub->InputAt(1), SUB));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00004232 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004233 break;
4234 }
Calin Juravle11351682014-10-23 15:38:15 +01004235 case Primitive::kPrimFloat:
4236 case Primitive::kPrimDouble: {
4237 locations->SetInAt(0, Location::RequiresFpuRegister());
4238 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004239 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004240 break;
Calin Juravle11351682014-10-23 15:38:15 +01004241 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004242 default:
Calin Juravle11351682014-10-23 15:38:15 +01004243 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004244 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004245}
4246
4247void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
4248 LocationSummary* locations = sub->GetLocations();
Calin Juravle11351682014-10-23 15:38:15 +01004249 Location out = locations->Out();
4250 Location first = locations->InAt(0);
4251 Location second = locations->InAt(1);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004252 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004253 case Primitive::kPrimInt: {
Calin Juravle11351682014-10-23 15:38:15 +01004254 if (second.IsRegister()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004255 __ sub(out.AsRegister<Register>(),
4256 first.AsRegister<Register>(),
4257 ShifterOperand(second.AsRegister<Register>()));
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004258 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004259 __ AddConstant(out.AsRegister<Register>(),
4260 first.AsRegister<Register>(),
Calin Juravle11351682014-10-23 15:38:15 +01004261 -second.GetConstant()->AsIntConstant()->GetValue());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004262 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004263 break;
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004264 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004265
Calin Juravle11351682014-10-23 15:38:15 +01004266 case Primitive::kPrimLong: {
Vladimir Marko59751a72016-08-05 14:37:27 +01004267 if (second.IsConstant()) {
4268 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
4269 GenerateAddLongConst(out, first, -value);
4270 } else {
4271 DCHECK(second.IsRegisterPair());
4272 __ subs(out.AsRegisterPairLow<Register>(),
4273 first.AsRegisterPairLow<Register>(),
4274 ShifterOperand(second.AsRegisterPairLow<Register>()));
4275 __ sbc(out.AsRegisterPairHigh<Register>(),
4276 first.AsRegisterPairHigh<Register>(),
4277 ShifterOperand(second.AsRegisterPairHigh<Register>()));
4278 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004279 break;
Calin Juravle11351682014-10-23 15:38:15 +01004280 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004281
Calin Juravle11351682014-10-23 15:38:15 +01004282 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004283 __ vsubs(out.AsFpuRegister<SRegister>(),
4284 first.AsFpuRegister<SRegister>(),
4285 second.AsFpuRegister<SRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004286 break;
Calin Juravle11351682014-10-23 15:38:15 +01004287 }
4288
4289 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004290 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4291 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4292 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravle11351682014-10-23 15:38:15 +01004293 break;
4294 }
4295
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01004296
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004297 default:
Calin Juravle11351682014-10-23 15:38:15 +01004298 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01004299 }
4300}
4301
Calin Juravle34bacdf2014-10-07 20:23:36 +01004302void LocationsBuilderARM::VisitMul(HMul* mul) {
4303 LocationSummary* locations =
4304 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
4305 switch (mul->GetResultType()) {
4306 case Primitive::kPrimInt:
4307 case Primitive::kPrimLong: {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004308 locations->SetInAt(0, Location::RequiresRegister());
4309 locations->SetInAt(1, Location::RequiresRegister());
4310 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01004311 break;
4312 }
4313
Calin Juravleb5bfa962014-10-21 18:02:24 +01004314 case Primitive::kPrimFloat:
4315 case Primitive::kPrimDouble: {
4316 locations->SetInAt(0, Location::RequiresFpuRegister());
4317 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004318 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Calin Juravle34bacdf2014-10-07 20:23:36 +01004319 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01004320 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01004321
4322 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01004323 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01004324 }
4325}
4326
4327void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
4328 LocationSummary* locations = mul->GetLocations();
4329 Location out = locations->Out();
4330 Location first = locations->InAt(0);
4331 Location second = locations->InAt(1);
4332 switch (mul->GetResultType()) {
4333 case Primitive::kPrimInt: {
Roland Levillain199f3362014-11-27 17:15:16 +00004334 __ mul(out.AsRegister<Register>(),
4335 first.AsRegister<Register>(),
4336 second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01004337 break;
4338 }
4339 case Primitive::kPrimLong: {
4340 Register out_hi = out.AsRegisterPairHigh<Register>();
4341 Register out_lo = out.AsRegisterPairLow<Register>();
4342 Register in1_hi = first.AsRegisterPairHigh<Register>();
4343 Register in1_lo = first.AsRegisterPairLow<Register>();
4344 Register in2_hi = second.AsRegisterPairHigh<Register>();
4345 Register in2_lo = second.AsRegisterPairLow<Register>();
4346
4347 // Extra checks to protect caused by the existence of R1_R2.
4348 // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
4349 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
4350 DCHECK_NE(out_hi, in1_lo);
4351 DCHECK_NE(out_hi, in2_lo);
4352
4353 // input: in1 - 64 bits, in2 - 64 bits
4354 // output: out
4355 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
4356 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
4357 // parts: out.lo = (in1.lo * in2.lo)[31:0]
4358
4359 // IP <- in1.lo * in2.hi
4360 __ mul(IP, in1_lo, in2_hi);
4361 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
4362 __ mla(out_hi, in1_hi, in2_lo, IP);
4363 // out.lo <- (in1.lo * in2.lo)[31:0];
4364 __ umull(out_lo, IP, in1_lo, in2_lo);
4365 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
4366 __ add(out_hi, out_hi, ShifterOperand(IP));
4367 break;
4368 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01004369
4370 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004371 __ vmuls(out.AsFpuRegister<SRegister>(),
4372 first.AsFpuRegister<SRegister>(),
4373 second.AsFpuRegister<SRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01004374 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01004375 }
4376
4377 case Primitive::kPrimDouble: {
Nicolas Geoffray1ba0f592014-10-27 15:14:55 +00004378 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4379 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4380 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
Calin Juravleb5bfa962014-10-21 18:02:24 +01004381 break;
4382 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01004383
4384 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01004385 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01004386 }
4387}
4388
Zheng Xuc6667102015-05-15 16:08:45 +08004389void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
4390 DCHECK(instruction->IsDiv() || instruction->IsRem());
4391 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4392
4393 LocationSummary* locations = instruction->GetLocations();
4394 Location second = locations->InAt(1);
4395 DCHECK(second.IsConstant());
4396
4397 Register out = locations->Out().AsRegister<Register>();
4398 Register dividend = locations->InAt(0).AsRegister<Register>();
4399 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4400 DCHECK(imm == 1 || imm == -1);
4401
4402 if (instruction->IsRem()) {
4403 __ LoadImmediate(out, 0);
4404 } else {
4405 if (imm == 1) {
4406 __ Mov(out, dividend);
4407 } else {
4408 __ rsb(out, dividend, ShifterOperand(0));
4409 }
4410 }
4411}
4412
4413void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
4414 DCHECK(instruction->IsDiv() || instruction->IsRem());
4415 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4416
4417 LocationSummary* locations = instruction->GetLocations();
4418 Location second = locations->InAt(1);
4419 DCHECK(second.IsConstant());
4420
4421 Register out = locations->Out().AsRegister<Register>();
4422 Register dividend = locations->InAt(0).AsRegister<Register>();
4423 Register temp = locations->GetTemp(0).AsRegister<Register>();
4424 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004425 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Zheng Xuc6667102015-05-15 16:08:45 +08004426 int ctz_imm = CTZ(abs_imm);
4427
4428 if (ctz_imm == 1) {
4429 __ Lsr(temp, dividend, 32 - ctz_imm);
4430 } else {
4431 __ Asr(temp, dividend, 31);
4432 __ Lsr(temp, temp, 32 - ctz_imm);
4433 }
4434 __ add(out, temp, ShifterOperand(dividend));
4435
4436 if (instruction->IsDiv()) {
4437 __ Asr(out, out, ctz_imm);
4438 if (imm < 0) {
4439 __ rsb(out, out, ShifterOperand(0));
4440 }
4441 } else {
4442 __ ubfx(out, out, 0, ctz_imm);
4443 __ sub(out, out, ShifterOperand(temp));
4444 }
4445}
4446
4447void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
4448 DCHECK(instruction->IsDiv() || instruction->IsRem());
4449 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4450
4451 LocationSummary* locations = instruction->GetLocations();
4452 Location second = locations->InAt(1);
4453 DCHECK(second.IsConstant());
4454
4455 Register out = locations->Out().AsRegister<Register>();
4456 Register dividend = locations->InAt(0).AsRegister<Register>();
4457 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
4458 Register temp2 = locations->GetTemp(1).AsRegister<Register>();
4459 int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4460
4461 int64_t magic;
4462 int shift;
4463 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
4464
4465 __ LoadImmediate(temp1, magic);
4466 __ smull(temp2, temp1, dividend, temp1);
4467
4468 if (imm > 0 && magic < 0) {
4469 __ add(temp1, temp1, ShifterOperand(dividend));
4470 } else if (imm < 0 && magic > 0) {
4471 __ sub(temp1, temp1, ShifterOperand(dividend));
4472 }
4473
4474 if (shift != 0) {
4475 __ Asr(temp1, temp1, shift);
4476 }
4477
4478 if (instruction->IsDiv()) {
4479 __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
4480 } else {
4481 __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
4482 // TODO: Strength reduction for mls.
4483 __ LoadImmediate(temp2, imm);
4484 __ mls(out, temp1, temp2, dividend);
4485 }
4486}
4487
4488void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
4489 DCHECK(instruction->IsDiv() || instruction->IsRem());
4490 DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
4491
4492 LocationSummary* locations = instruction->GetLocations();
4493 Location second = locations->InAt(1);
4494 DCHECK(second.IsConstant());
4495
4496 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4497 if (imm == 0) {
4498 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
4499 } else if (imm == 1 || imm == -1) {
4500 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004501 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004502 DivRemByPowerOfTwo(instruction);
4503 } else {
4504 DCHECK(imm <= -2 || imm >= 2);
4505 GenerateDivRemWithAnyConstant(instruction);
4506 }
4507}
4508
Calin Juravle7c4954d2014-10-28 16:57:40 +00004509void LocationsBuilderARM::VisitDiv(HDiv* div) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004510 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4511 if (div->GetResultType() == Primitive::kPrimLong) {
4512 // pLdiv runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004513 call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004514 } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
4515 // sdiv will be replaced by other instruction sequence.
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004516 } else if (div->GetResultType() == Primitive::kPrimInt &&
4517 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
4518 // pIdivmod runtime call.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004519 call_kind = LocationSummary::kCallOnMainOnly;
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004520 }
4521
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004522 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
4523
Calin Juravle7c4954d2014-10-28 16:57:40 +00004524 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004525 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004526 if (div->InputAt(1)->IsConstant()) {
4527 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004528 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004529 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004530 int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
4531 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004532 // No temp register required.
4533 } else {
4534 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004535 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004536 locations->AddTemp(Location::RequiresRegister());
4537 }
4538 }
4539 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004540 locations->SetInAt(0, Location::RequiresRegister());
4541 locations->SetInAt(1, Location::RequiresRegister());
4542 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4543 } else {
4544 InvokeRuntimeCallingConvention calling_convention;
4545 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4546 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004547 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004548 // we only need the former.
4549 locations->SetOut(Location::RegisterLocation(R0));
4550 }
Calin Juravled0d48522014-11-04 16:40:20 +00004551 break;
4552 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00004553 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004554 InvokeRuntimeCallingConvention calling_convention;
4555 locations->SetInAt(0, Location::RegisterPairLocation(
4556 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4557 locations->SetInAt(1, Location::RegisterPairLocation(
4558 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004559 locations->SetOut(Location::RegisterPairLocation(R0, R1));
Calin Juravle7c4954d2014-10-28 16:57:40 +00004560 break;
4561 }
4562 case Primitive::kPrimFloat:
4563 case Primitive::kPrimDouble: {
4564 locations->SetInAt(0, Location::RequiresFpuRegister());
4565 locations->SetInAt(1, Location::RequiresFpuRegister());
4566 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4567 break;
4568 }
4569
4570 default:
4571 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4572 }
4573}
4574
4575void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) {
4576 LocationSummary* locations = div->GetLocations();
4577 Location out = locations->Out();
4578 Location first = locations->InAt(0);
4579 Location second = locations->InAt(1);
4580
4581 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00004582 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004583 if (second.IsConstant()) {
4584 GenerateDivRemConstantIntegral(div);
4585 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004586 __ sdiv(out.AsRegister<Register>(),
4587 first.AsRegister<Register>(),
4588 second.AsRegister<Register>());
4589 } else {
4590 InvokeRuntimeCallingConvention calling_convention;
4591 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4592 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4593 DCHECK_EQ(R0, out.AsRegister<Register>());
4594
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004595 codegen_->InvokeRuntime(kQuickIdivmod, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004596 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004597 }
Calin Juravled0d48522014-11-04 16:40:20 +00004598 break;
4599 }
4600
Calin Juravle7c4954d2014-10-28 16:57:40 +00004601 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004602 InvokeRuntimeCallingConvention calling_convention;
4603 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
4604 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
4605 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
4606 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
4607 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>());
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00004608 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004609
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004610 codegen_->InvokeRuntime(kQuickLdiv, div, div->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004611 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
Calin Juravle7c4954d2014-10-28 16:57:40 +00004612 break;
4613 }
4614
4615 case Primitive::kPrimFloat: {
Roland Levillain199f3362014-11-27 17:15:16 +00004616 __ vdivs(out.AsFpuRegister<SRegister>(),
4617 first.AsFpuRegister<SRegister>(),
4618 second.AsFpuRegister<SRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00004619 break;
4620 }
4621
4622 case Primitive::kPrimDouble: {
4623 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
4624 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()),
4625 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>()));
4626 break;
4627 }
4628
4629 default:
4630 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
4631 }
4632}
4633
Calin Juravlebacfec32014-11-14 15:54:36 +00004634void LocationsBuilderARM::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004635 Primitive::Type type = rem->GetResultType();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004636
4637 // Most remainders are implemented in the runtime.
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004638 LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
Zheng Xuc6667102015-05-15 16:08:45 +08004639 if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
4640 // sdiv will be replaced by other instruction sequence.
4641 call_kind = LocationSummary::kNoCall;
4642 } else if ((rem->GetResultType() == Primitive::kPrimInt)
4643 && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004644 // Have hardware divide instruction for int, do it with three instructions.
4645 call_kind = LocationSummary::kNoCall;
4646 }
4647
Calin Juravlebacfec32014-11-14 15:54:36 +00004648 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
4649
Calin Juravled2ec87d2014-12-08 14:24:46 +00004650 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004651 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004652 if (rem->InputAt(1)->IsConstant()) {
4653 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko13c86fd2015-11-11 12:37:46 +00004654 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
Zheng Xuc6667102015-05-15 16:08:45 +08004655 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004656 int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
4657 if (value == 1 || value == 0 || value == -1) {
Zheng Xuc6667102015-05-15 16:08:45 +08004658 // No temp register required.
4659 } else {
4660 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004661 if (!IsPowerOfTwo(AbsOrMin(value))) {
Zheng Xuc6667102015-05-15 16:08:45 +08004662 locations->AddTemp(Location::RequiresRegister());
4663 }
4664 }
4665 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004666 locations->SetInAt(0, Location::RequiresRegister());
4667 locations->SetInAt(1, Location::RequiresRegister());
4668 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4669 locations->AddTemp(Location::RequiresRegister());
4670 } else {
4671 InvokeRuntimeCallingConvention calling_convention;
4672 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4673 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Roland Levillain5e8d5f02016-10-18 18:03:43 +01004674 // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004675 // we only need the latter.
4676 locations->SetOut(Location::RegisterLocation(R1));
4677 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004678 break;
4679 }
4680 case Primitive::kPrimLong: {
4681 InvokeRuntimeCallingConvention calling_convention;
4682 locations->SetInAt(0, Location::RegisterPairLocation(
4683 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4684 locations->SetInAt(1, Location::RegisterPairLocation(
4685 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4686 // The runtime helper puts the output in R2,R3.
4687 locations->SetOut(Location::RegisterPairLocation(R2, R3));
4688 break;
4689 }
Calin Juravled2ec87d2014-12-08 14:24:46 +00004690 case Primitive::kPrimFloat: {
4691 InvokeRuntimeCallingConvention calling_convention;
4692 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
4693 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
4694 locations->SetOut(Location::FpuRegisterLocation(S0));
4695 break;
4696 }
4697
Calin Juravlebacfec32014-11-14 15:54:36 +00004698 case Primitive::kPrimDouble: {
Calin Juravled2ec87d2014-12-08 14:24:46 +00004699 InvokeRuntimeCallingConvention calling_convention;
4700 locations->SetInAt(0, Location::FpuRegisterPairLocation(
4701 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1)));
4702 locations->SetInAt(1, Location::FpuRegisterPairLocation(
4703 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3)));
4704 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1));
Calin Juravlebacfec32014-11-14 15:54:36 +00004705 break;
4706 }
4707
4708 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004709 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004710 }
4711}
4712
4713void InstructionCodeGeneratorARM::VisitRem(HRem* rem) {
4714 LocationSummary* locations = rem->GetLocations();
4715 Location out = locations->Out();
4716 Location first = locations->InAt(0);
4717 Location second = locations->InAt(1);
4718
Calin Juravled2ec87d2014-12-08 14:24:46 +00004719 Primitive::Type type = rem->GetResultType();
4720 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00004721 case Primitive::kPrimInt: {
Zheng Xuc6667102015-05-15 16:08:45 +08004722 if (second.IsConstant()) {
4723 GenerateDivRemConstantIntegral(rem);
4724 } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004725 Register reg1 = first.AsRegister<Register>();
4726 Register reg2 = second.AsRegister<Register>();
4727 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004728
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004729 // temp = reg1 / reg2 (integer division)
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004730 // dest = reg1 - temp * reg2
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004731 __ sdiv(temp, reg1, reg2);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +01004732 __ mls(out.AsRegister<Register>(), temp, reg2, reg1);
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004733 } else {
4734 InvokeRuntimeCallingConvention calling_convention;
4735 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>());
4736 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>());
4737 DCHECK_EQ(R1, out.AsRegister<Register>());
4738
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004739 codegen_->InvokeRuntime(kQuickIdivmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004740 CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>();
Andreas Gampeb51cdb32015-03-29 17:32:48 -07004741 }
Calin Juravlebacfec32014-11-14 15:54:36 +00004742 break;
4743 }
4744
4745 case Primitive::kPrimLong: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004746 codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004747 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004748 break;
4749 }
4750
Calin Juravled2ec87d2014-12-08 14:24:46 +00004751 case Primitive::kPrimFloat: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004752 codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004753 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Calin Juravled2ec87d2014-12-08 14:24:46 +00004754 break;
4755 }
4756
Calin Juravlebacfec32014-11-14 15:54:36 +00004757 case Primitive::kPrimDouble: {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01004758 codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004759 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Calin Juravlebacfec32014-11-14 15:54:36 +00004760 break;
4761 }
4762
4763 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00004764 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00004765 }
4766}
4767
Calin Juravled0d48522014-11-04 16:40:20 +00004768void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004769 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004770 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Calin Juravled0d48522014-11-04 16:40:20 +00004771}
4772
4773void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01004774 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00004775 codegen_->AddSlowPath(slow_path);
4776
4777 LocationSummary* locations = instruction->GetLocations();
4778 Location value = locations->InAt(0);
4779
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004780 switch (instruction->GetType()) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00004781 case Primitive::kPrimBoolean:
Serguei Katkov8c0676c2015-08-03 13:55:33 +06004782 case Primitive::kPrimByte:
4783 case Primitive::kPrimChar:
4784 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004785 case Primitive::kPrimInt: {
4786 if (value.IsRegister()) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01004787 __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00004788 } else {
4789 DCHECK(value.IsConstant()) << value;
4790 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
4791 __ b(slow_path->GetEntryLabel());
4792 }
4793 }
4794 break;
4795 }
4796 case Primitive::kPrimLong: {
4797 if (value.IsRegisterPair()) {
4798 __ orrs(IP,
4799 value.AsRegisterPairLow<Register>(),
4800 ShifterOperand(value.AsRegisterPairHigh<Register>()));
4801 __ b(slow_path->GetEntryLabel(), EQ);
4802 } else {
4803 DCHECK(value.IsConstant()) << value;
4804 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4805 __ b(slow_path->GetEntryLabel());
4806 }
4807 }
4808 break;
4809 default:
4810 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
4811 }
4812 }
Calin Juravled0d48522014-11-04 16:40:20 +00004813}
4814
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004815void InstructionCodeGeneratorARM::HandleIntegerRotate(LocationSummary* locations) {
4816 Register in = locations->InAt(0).AsRegister<Register>();
4817 Location rhs = locations->InAt(1);
4818 Register out = locations->Out().AsRegister<Register>();
4819
4820 if (rhs.IsConstant()) {
4821 // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31],
4822 // so map all rotations to a +ve. equivalent in that range.
4823 // (e.g. left *or* right by -2 bits == 30 bits in the same direction.)
4824 uint32_t rot = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()) & 0x1F;
4825 if (rot) {
4826 // Rotate, mapping left rotations to right equivalents if necessary.
4827 // (e.g. left by 2 bits == right by 30.)
4828 __ Ror(out, in, rot);
4829 } else if (out != in) {
4830 __ Mov(out, in);
4831 }
4832 } else {
4833 __ Ror(out, in, rhs.AsRegister<Register>());
4834 }
4835}
4836
4837// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer
4838// rotates by swapping input regs (effectively rotating by the first 32-bits of
4839// a larger rotation) or flipping direction (thus treating larger right/left
4840// rotations as sub-word sized rotations in the other direction) as appropriate.
Anton Kirilov6f644202017-02-27 18:29:45 +00004841void InstructionCodeGeneratorARM::HandleLongRotate(HRor* ror) {
4842 LocationSummary* locations = ror->GetLocations();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004843 Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>();
4844 Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
4845 Location rhs = locations->InAt(1);
4846 Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>();
4847 Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>();
4848
4849 if (rhs.IsConstant()) {
4850 uint64_t rot = CodeGenerator::GetInt64ValueOf(rhs.GetConstant());
4851 // Map all rotations to +ve. equivalents on the interval [0,63].
Roland Levillain5b5b9312016-03-22 14:57:31 +00004852 rot &= kMaxLongShiftDistance;
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004853 // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate
4854 // logic below to a simple pair of binary orr.
4855 // (e.g. 34 bits == in_reg swap + 2 bits right.)
4856 if (rot >= kArmBitsPerWord) {
4857 rot -= kArmBitsPerWord;
4858 std::swap(in_reg_hi, in_reg_lo);
4859 }
4860 // Rotate, or mov to out for zero or word size rotations.
4861 if (rot != 0u) {
4862 __ Lsr(out_reg_hi, in_reg_hi, rot);
4863 __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, kArmBitsPerWord - rot));
4864 __ Lsr(out_reg_lo, in_reg_lo, rot);
4865 __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, kArmBitsPerWord - rot));
4866 } else {
4867 __ Mov(out_reg_lo, in_reg_lo);
4868 __ Mov(out_reg_hi, in_reg_hi);
4869 }
4870 } else {
4871 Register shift_right = locations->GetTemp(0).AsRegister<Register>();
4872 Register shift_left = locations->GetTemp(1).AsRegister<Register>();
4873 Label end;
4874 Label shift_by_32_plus_shift_right;
Anton Kirilov6f644202017-02-27 18:29:45 +00004875 Label* final_label = codegen_->GetFinalLabel(ror, &end);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004876
4877 __ and_(shift_right, rhs.AsRegister<Register>(), ShifterOperand(0x1F));
4878 __ Lsrs(shift_left, rhs.AsRegister<Register>(), 6);
4879 __ rsb(shift_left, shift_right, ShifterOperand(kArmBitsPerWord), AL, kCcKeep);
4880 __ b(&shift_by_32_plus_shift_right, CC);
4881
4882 // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
4883 // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right).
4884 __ Lsl(out_reg_hi, in_reg_hi, shift_left);
4885 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4886 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4887 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4888 __ Lsr(shift_left, in_reg_hi, shift_right);
4889 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left));
Anton Kirilov6f644202017-02-27 18:29:45 +00004890 __ b(final_label);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004891
4892 __ Bind(&shift_by_32_plus_shift_right); // Shift by 32+shift_right.
4893 // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left).
4894 // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left).
4895 __ Lsr(out_reg_hi, in_reg_hi, shift_right);
4896 __ Lsl(out_reg_lo, in_reg_lo, shift_left);
4897 __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo));
4898 __ Lsr(out_reg_lo, in_reg_lo, shift_right);
4899 __ Lsl(shift_right, in_reg_hi, shift_left);
4900 __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right));
4901
Anton Kirilov6f644202017-02-27 18:29:45 +00004902 if (end.IsLinked()) {
4903 __ Bind(&end);
4904 }
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004905 }
4906}
Roland Levillain22c49222016-03-18 14:04:28 +00004907
4908void LocationsBuilderARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004909 LocationSummary* locations =
4910 new (GetGraph()->GetArena()) LocationSummary(ror, LocationSummary::kNoCall);
4911 switch (ror->GetResultType()) {
4912 case Primitive::kPrimInt: {
4913 locations->SetInAt(0, Location::RequiresRegister());
4914 locations->SetInAt(1, Location::RegisterOrConstant(ror->InputAt(1)));
4915 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4916 break;
4917 }
4918 case Primitive::kPrimLong: {
4919 locations->SetInAt(0, Location::RequiresRegister());
4920 if (ror->InputAt(1)->IsConstant()) {
4921 locations->SetInAt(1, Location::ConstantLocation(ror->InputAt(1)->AsConstant()));
4922 } else {
4923 locations->SetInAt(1, Location::RequiresRegister());
4924 locations->AddTemp(Location::RequiresRegister());
4925 locations->AddTemp(Location::RequiresRegister());
4926 }
4927 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4928 break;
4929 }
4930 default:
4931 LOG(FATAL) << "Unexpected operation type " << ror->GetResultType();
4932 }
4933}
4934
Roland Levillain22c49222016-03-18 14:04:28 +00004935void InstructionCodeGeneratorARM::VisitRor(HRor* ror) {
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004936 LocationSummary* locations = ror->GetLocations();
4937 Primitive::Type type = ror->GetResultType();
4938 switch (type) {
4939 case Primitive::kPrimInt: {
4940 HandleIntegerRotate(locations);
4941 break;
4942 }
4943 case Primitive::kPrimLong: {
Anton Kirilov6f644202017-02-27 18:29:45 +00004944 HandleLongRotate(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004945 break;
4946 }
4947 default:
4948 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko351dddf2015-12-11 16:34:46 +00004949 UNREACHABLE();
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004950 }
4951}
4952
Calin Juravle9aec02f2014-11-18 23:06:35 +00004953void LocationsBuilderARM::HandleShift(HBinaryOperation* op) {
4954 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4955
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004956 LocationSummary* locations =
4957 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
Calin Juravle9aec02f2014-11-18 23:06:35 +00004958
4959 switch (op->GetResultType()) {
4960 case Primitive::kPrimInt: {
4961 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004962 if (op->InputAt(1)->IsConstant()) {
4963 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4964 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4965 } else {
4966 locations->SetInAt(1, Location::RequiresRegister());
4967 // Make the output overlap, as it will be used to hold the masked
4968 // second input.
4969 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4970 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004971 break;
4972 }
4973 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00004974 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko33ad10e2015-11-10 19:31:26 +00004975 if (op->InputAt(1)->IsConstant()) {
4976 locations->SetInAt(1, Location::ConstantLocation(op->InputAt(1)->AsConstant()));
4977 // For simplicity, use kOutputOverlap even though we only require that low registers
4978 // don't clash with high registers which the register allocator currently guarantees.
4979 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4980 } else {
4981 locations->SetInAt(1, Location::RequiresRegister());
4982 locations->AddTemp(Location::RequiresRegister());
4983 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4984 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00004985 break;
4986 }
4987 default:
4988 LOG(FATAL) << "Unexpected operation type " << op->GetResultType();
4989 }
4990}
4991
4992void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) {
4993 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
4994
4995 LocationSummary* locations = op->GetLocations();
4996 Location out = locations->Out();
4997 Location first = locations->InAt(0);
4998 Location second = locations->InAt(1);
4999
5000 Primitive::Type type = op->GetResultType();
5001 switch (type) {
5002 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005003 Register out_reg = out.AsRegister<Register>();
5004 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00005005 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005006 Register second_reg = second.AsRegister<Register>();
Roland Levillainc9285912015-12-18 10:38:42 +00005007 // ARM doesn't mask the shift count so we need to do it ourselves.
Roland Levillain5b5b9312016-03-22 14:57:31 +00005008 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftDistance));
Calin Juravle9aec02f2014-11-18 23:06:35 +00005009 if (op->IsShl()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01005010 __ Lsl(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00005011 } else if (op->IsShr()) {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01005012 __ Asr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00005013 } else {
Nicolas Geoffraya4f35812015-06-22 23:12:45 +01005014 __ Lsr(out_reg, first_reg, out_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00005015 }
5016 } else {
5017 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00005018 uint32_t shift_value = cst & kMaxIntShiftDistance;
Roland Levillainc9285912015-12-18 10:38:42 +00005019 if (shift_value == 0) { // ARM does not support shifting with 0 immediate.
Calin Juravle9aec02f2014-11-18 23:06:35 +00005020 __ Mov(out_reg, first_reg);
5021 } else if (op->IsShl()) {
5022 __ Lsl(out_reg, first_reg, shift_value);
5023 } else if (op->IsShr()) {
5024 __ Asr(out_reg, first_reg, shift_value);
5025 } else {
5026 __ Lsr(out_reg, first_reg, shift_value);
5027 }
5028 }
5029 break;
5030 }
5031 case Primitive::kPrimLong: {
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005032 Register o_h = out.AsRegisterPairHigh<Register>();
5033 Register o_l = out.AsRegisterPairLow<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00005034
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005035 Register high = first.AsRegisterPairHigh<Register>();
5036 Register low = first.AsRegisterPairLow<Register>();
5037
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005038 if (second.IsRegister()) {
5039 Register temp = locations->GetTemp(0).AsRegister<Register>();
Guillaume "Vermeille" Sanchezfd18f5a2015-03-11 14:57:40 +00005040
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005041 Register second_reg = second.AsRegister<Register>();
5042
5043 if (op->IsShl()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00005044 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005045 // Shift the high part
5046 __ Lsl(o_h, high, o_l);
5047 // Shift the low part and `or` what overflew on the high part
5048 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord));
5049 __ Lsr(temp, low, temp);
5050 __ orr(o_h, o_h, ShifterOperand(temp));
5051 // If the shift is > 32 bits, override the high part
5052 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord));
5053 __ it(PL);
5054 __ Lsl(o_h, low, temp, PL);
5055 // Shift the low part
5056 __ Lsl(o_l, low, o_l);
5057 } else if (op->IsShr()) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00005058 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005059 // Shift the low part
5060 __ Lsr(o_l, low, o_h);
5061 // Shift the high part and `or` what underflew on the low part
5062 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
5063 __ Lsl(temp, high, temp);
5064 __ orr(o_l, o_l, ShifterOperand(temp));
5065 // If the shift is > 32 bits, override the low part
5066 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
5067 __ it(PL);
5068 __ Asr(o_l, high, temp, PL);
5069 // Shift the high part
5070 __ Asr(o_h, high, o_h);
5071 } else {
Roland Levillain5b5b9312016-03-22 14:57:31 +00005072 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftDistance));
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005073 // same as Shr except we use `Lsr`s and not `Asr`s
5074 __ Lsr(o_l, low, o_h);
5075 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord));
5076 __ Lsl(temp, high, temp);
5077 __ orr(o_l, o_l, ShifterOperand(temp));
5078 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord));
5079 __ it(PL);
5080 __ Lsr(o_l, high, temp, PL);
5081 __ Lsr(o_h, high, o_h);
5082 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005083 } else {
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005084 // Register allocator doesn't create partial overlap.
5085 DCHECK_NE(o_l, high);
5086 DCHECK_NE(o_h, low);
5087 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain5b5b9312016-03-22 14:57:31 +00005088 uint32_t shift_value = cst & kMaxLongShiftDistance;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005089 if (shift_value > 32) {
5090 if (op->IsShl()) {
5091 __ Lsl(o_h, low, shift_value - 32);
5092 __ LoadImmediate(o_l, 0);
5093 } else if (op->IsShr()) {
5094 __ Asr(o_l, high, shift_value - 32);
5095 __ Asr(o_h, high, 31);
5096 } else {
5097 __ Lsr(o_l, high, shift_value - 32);
5098 __ LoadImmediate(o_h, 0);
5099 }
5100 } else if (shift_value == 32) {
5101 if (op->IsShl()) {
5102 __ mov(o_h, ShifterOperand(low));
5103 __ LoadImmediate(o_l, 0);
5104 } else if (op->IsShr()) {
5105 __ mov(o_l, ShifterOperand(high));
5106 __ Asr(o_h, high, 31);
5107 } else {
5108 __ mov(o_l, ShifterOperand(high));
5109 __ LoadImmediate(o_h, 0);
5110 }
Vladimir Markof9d741e2015-11-20 15:08:11 +00005111 } else if (shift_value == 1) {
5112 if (op->IsShl()) {
5113 __ Lsls(o_l, low, 1);
5114 __ adc(o_h, high, ShifterOperand(high));
5115 } else if (op->IsShr()) {
5116 __ Asrs(o_h, high, 1);
5117 __ Rrx(o_l, low);
5118 } else {
5119 __ Lsrs(o_h, high, 1);
5120 __ Rrx(o_l, low);
5121 }
5122 } else {
5123 DCHECK(2 <= shift_value && shift_value < 32) << shift_value;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005124 if (op->IsShl()) {
5125 __ Lsl(o_h, high, shift_value);
5126 __ orr(o_h, o_h, ShifterOperand(low, LSR, 32 - shift_value));
5127 __ Lsl(o_l, low, shift_value);
5128 } else if (op->IsShr()) {
5129 __ Lsr(o_l, low, shift_value);
5130 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
5131 __ Asr(o_h, high, shift_value);
5132 } else {
5133 __ Lsr(o_l, low, shift_value);
5134 __ orr(o_l, o_l, ShifterOperand(high, LSL, 32 - shift_value));
5135 __ Lsr(o_h, high, shift_value);
5136 }
5137 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005138 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00005139 break;
5140 }
5141 default:
5142 LOG(FATAL) << "Unexpected operation type " << type;
Vladimir Marko33ad10e2015-11-10 19:31:26 +00005143 UNREACHABLE();
Calin Juravle9aec02f2014-11-18 23:06:35 +00005144 }
5145}
5146
5147void LocationsBuilderARM::VisitShl(HShl* shl) {
5148 HandleShift(shl);
5149}
5150
5151void InstructionCodeGeneratorARM::VisitShl(HShl* shl) {
5152 HandleShift(shl);
5153}
5154
5155void LocationsBuilderARM::VisitShr(HShr* shr) {
5156 HandleShift(shr);
5157}
5158
5159void InstructionCodeGeneratorARM::VisitShr(HShr* shr) {
5160 HandleShift(shr);
5161}
5162
5163void LocationsBuilderARM::VisitUShr(HUShr* ushr) {
5164 HandleShift(ushr);
5165}
5166
5167void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) {
5168 HandleShift(ushr);
5169}
5170
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01005171void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005172 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005173 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
David Brazdil6de19382016-01-08 17:37:10 +00005174 if (instruction->IsStringAlloc()) {
5175 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
5176 } else {
5177 InvokeRuntimeCallingConvention calling_convention;
5178 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00005179 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005180 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01005181}
5182
5183void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01005184 // Note: if heap poisoning is enabled, the entry point takes cares
5185 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00005186 if (instruction->IsStringAlloc()) {
5187 // String is allocated through StringFactory. Call NewEmptyString entry point.
5188 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07005189 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00005190 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
5191 __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value());
5192 __ blx(LR);
5193 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
5194 } else {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01005195 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00005196 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00005197 }
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01005198}
5199
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005200void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
5201 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005202 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005203 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005204 locations->SetOut(Location::RegisterLocation(R0));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00005205 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5206 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005207}
5208
5209void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
Roland Levillain4d027112015-07-01 15:41:14 +01005210 // Note: if heap poisoning is enabled, the entry point takes cares
5211 // of poisoning the reference.
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00005212 QuickEntrypointEnum entrypoint =
5213 CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
5214 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00005215 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Nicolas Geoffrayd0958442017-01-30 14:57:16 +00005216 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01005217}
5218
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005219void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005220 LocationSummary* locations =
5221 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01005222 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
5223 if (location.IsStackSlot()) {
5224 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5225 } else if (location.IsDoubleStackSlot()) {
5226 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005227 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01005228 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005229}
5230
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005231void InstructionCodeGeneratorARM::VisitParameterValue(
5232 HParameterValue* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01005233 // Nothing to do, the parameter is already at its location.
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005234}
5235
5236void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
5237 LocationSummary* locations =
5238 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5239 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
5240}
5241
5242void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
5243 // Nothing to do, the method is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01005244}
5245
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005246void LocationsBuilderARM::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005247 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005248 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005249 locations->SetInAt(0, Location::RequiresRegister());
5250 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01005251}
5252
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005253void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
5254 LocationSummary* locations = not_->GetLocations();
5255 Location out = locations->Out();
5256 Location in = locations->InAt(0);
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00005257 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005258 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00005259 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005260 break;
5261
5262 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01005263 __ mvn(out.AsRegisterPairLow<Register>(),
5264 ShifterOperand(in.AsRegisterPairLow<Register>()));
5265 __ mvn(out.AsRegisterPairHigh<Register>(),
5266 ShifterOperand(in.AsRegisterPairHigh<Register>()));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01005267 break;
5268
5269 default:
5270 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
5271 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01005272}
5273
David Brazdil66d126e2015-04-03 16:02:44 +01005274void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) {
5275 LocationSummary* locations =
5276 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
5277 locations->SetInAt(0, Location::RequiresRegister());
5278 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5279}
5280
5281void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01005282 LocationSummary* locations = bool_not->GetLocations();
5283 Location out = locations->Out();
5284 Location in = locations->InAt(0);
5285 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1));
5286}
5287
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005288void LocationsBuilderARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005289 LocationSummary* locations =
5290 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00005291 switch (compare->InputAt(0)->GetType()) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00005292 case Primitive::kPrimBoolean:
5293 case Primitive::kPrimByte:
5294 case Primitive::kPrimShort:
5295 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08005296 case Primitive::kPrimInt:
Calin Juravleddb7df22014-11-25 20:56:51 +00005297 case Primitive::kPrimLong: {
5298 locations->SetInAt(0, Location::RequiresRegister());
5299 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005300 // Output overlaps because it is written before doing the low comparison.
5301 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Calin Juravleddb7df22014-11-25 20:56:51 +00005302 break;
5303 }
5304 case Primitive::kPrimFloat:
5305 case Primitive::kPrimDouble: {
5306 locations->SetInAt(0, Location::RequiresFpuRegister());
Vladimir Marko37dd80d2016-08-01 17:41:45 +01005307 locations->SetInAt(1, ArithmeticZeroOrFpuRegister(compare->InputAt(1)));
Calin Juravleddb7df22014-11-25 20:56:51 +00005308 locations->SetOut(Location::RequiresRegister());
5309 break;
5310 }
5311 default:
5312 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
5313 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005314}
5315
5316void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005317 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005318 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00005319 Location left = locations->InAt(0);
5320 Location right = locations->InAt(1);
5321
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005322 Label less, greater, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00005323 Label* final_label = codegen_->GetFinalLabel(compare, &done);
Calin Juravleddb7df22014-11-25 20:56:51 +00005324 Primitive::Type type = compare->InputAt(0)->GetType();
Vladimir Markod6e069b2016-01-18 11:11:01 +00005325 Condition less_cond;
Calin Juravleddb7df22014-11-25 20:56:51 +00005326 switch (type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00005327 case Primitive::kPrimBoolean:
5328 case Primitive::kPrimByte:
5329 case Primitive::kPrimShort:
5330 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08005331 case Primitive::kPrimInt: {
5332 __ LoadImmediate(out, 0);
5333 __ cmp(left.AsRegister<Register>(),
5334 ShifterOperand(right.AsRegister<Register>())); // Signed compare.
5335 less_cond = LT;
5336 break;
5337 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005338 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005339 __ cmp(left.AsRegisterPairHigh<Register>(),
5340 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare.
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005341 __ b(&less, LT);
5342 __ b(&greater, GT);
Roland Levillain4fa13f62015-07-06 18:11:54 +01005343 // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
Calin Juravleddb7df22014-11-25 20:56:51 +00005344 __ LoadImmediate(out, 0);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01005345 __ cmp(left.AsRegisterPairLow<Register>(),
5346 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare.
Vladimir Markod6e069b2016-01-18 11:11:01 +00005347 less_cond = LO;
Calin Juravleddb7df22014-11-25 20:56:51 +00005348 break;
5349 }
5350 case Primitive::kPrimFloat:
5351 case Primitive::kPrimDouble: {
5352 __ LoadImmediate(out, 0);
Donghui Bai426b49c2016-11-08 14:55:38 +08005353 GenerateVcmp(compare, codegen_);
Calin Juravleddb7df22014-11-25 20:56:51 +00005354 __ vmstat(); // transfer FP status register to ARM APSR.
Vladimir Markod6e069b2016-01-18 11:11:01 +00005355 less_cond = ARMFPCondition(kCondLT, compare->IsGtBias());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005356 break;
5357 }
5358 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00005359 LOG(FATAL) << "Unexpected compare type " << type;
Vladimir Markod6e069b2016-01-18 11:11:01 +00005360 UNREACHABLE();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005361 }
Aart Bika19616e2016-02-01 18:57:58 -08005362
Anton Kirilov6f644202017-02-27 18:29:45 +00005363 __ b(final_label, EQ);
Vladimir Markod6e069b2016-01-18 11:11:01 +00005364 __ b(&less, less_cond);
Calin Juravleddb7df22014-11-25 20:56:51 +00005365
5366 __ Bind(&greater);
5367 __ LoadImmediate(out, 1);
Anton Kirilov6f644202017-02-27 18:29:45 +00005368 __ b(final_label);
Calin Juravleddb7df22014-11-25 20:56:51 +00005369
5370 __ Bind(&less);
5371 __ LoadImmediate(out, -1);
5372
Anton Kirilov6f644202017-02-27 18:29:45 +00005373 if (done.IsLinked()) {
5374 __ Bind(&done);
5375 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01005376}
5377
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005378void LocationsBuilderARM::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01005379 LocationSummary* locations =
5380 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Vladimir Marko372f10e2016-05-17 16:30:10 +01005381 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01005382 locations->SetInAt(i, Location::Any());
5383 }
5384 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005385}
5386
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01005387void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01005388 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01005389}
5390
Roland Levillainc9285912015-12-18 10:38:42 +00005391void CodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
5392 // TODO (ported from quick): revisit ARM barrier kinds.
5393 DmbOptions flavor = DmbOptions::ISH; // Quiet C++ warnings.
Calin Juravle52c48962014-12-16 17:02:57 +00005394 switch (kind) {
5395 case MemBarrierKind::kAnyStore:
5396 case MemBarrierKind::kLoadAny:
5397 case MemBarrierKind::kAnyAny: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005398 flavor = DmbOptions::ISH;
Calin Juravle52c48962014-12-16 17:02:57 +00005399 break;
5400 }
5401 case MemBarrierKind::kStoreStore: {
Kenny Root1d8199d2015-06-02 11:01:10 -07005402 flavor = DmbOptions::ISHST;
Calin Juravle52c48962014-12-16 17:02:57 +00005403 break;
5404 }
5405 default:
5406 LOG(FATAL) << "Unexpected memory barrier " << kind;
5407 }
Kenny Root1d8199d2015-06-02 11:01:10 -07005408 __ dmb(flavor);
Calin Juravle52c48962014-12-16 17:02:57 +00005409}
5410
5411void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
5412 uint32_t offset,
5413 Register out_lo,
5414 Register out_hi) {
5415 if (offset != 0) {
Roland Levillain3b359c72015-11-17 19:35:12 +00005416 // Ensure `out_lo` is different from `addr`, so that loading
5417 // `offset` into `out_lo` does not clutter `addr`.
5418 DCHECK_NE(out_lo, addr);
Calin Juravle52c48962014-12-16 17:02:57 +00005419 __ LoadImmediate(out_lo, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005420 __ add(IP, addr, ShifterOperand(out_lo));
5421 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005422 }
5423 __ ldrexd(out_lo, out_hi, addr);
5424}
5425
5426void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr,
5427 uint32_t offset,
5428 Register value_lo,
5429 Register value_hi,
5430 Register temp1,
Calin Juravle77520bc2015-01-12 18:45:46 +00005431 Register temp2,
5432 HInstruction* instruction) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00005433 Label fail;
Calin Juravle52c48962014-12-16 17:02:57 +00005434 if (offset != 0) {
5435 __ LoadImmediate(temp1, offset);
Nicolas Geoffraybdcedd32015-01-09 08:48:29 +00005436 __ add(IP, addr, ShifterOperand(temp1));
5437 addr = IP;
Calin Juravle52c48962014-12-16 17:02:57 +00005438 }
5439 __ Bind(&fail);
5440 // We need a load followed by store. (The address used in a STREX instruction must
5441 // be the same as the address in the most recently executed LDREX instruction.)
5442 __ ldrexd(temp1, temp2, addr);
Calin Juravle77520bc2015-01-12 18:45:46 +00005443 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005444 __ strexd(temp1, value_lo, value_hi, addr);
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005445 __ CompareAndBranchIfNonZero(temp1, &fail);
Calin Juravle52c48962014-12-16 17:02:57 +00005446}
5447
5448void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5449 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5450
Nicolas Geoffray39468442014-09-02 15:17:15 +01005451 LocationSummary* locations =
5452 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005453 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005454
Calin Juravle52c48962014-12-16 17:02:57 +00005455 Primitive::Type field_type = field_info.GetFieldType();
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005456 if (Primitive::IsFloatingPointType(field_type)) {
5457 locations->SetInAt(1, Location::RequiresFpuRegister());
5458 } else {
5459 locations->SetInAt(1, Location::RequiresRegister());
5460 }
5461
Calin Juravle52c48962014-12-16 17:02:57 +00005462 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble;
Calin Juravle34166012014-12-19 17:22:29 +00005463 bool generate_volatile = field_info.IsVolatile()
5464 && is_wide
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005465 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain4d027112015-07-01 15:41:14 +01005466 bool needs_write_barrier =
5467 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005468 // Temporary registers for the write barrier.
Calin Juravle52c48962014-12-16 17:02:57 +00005469 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
Roland Levillain4d027112015-07-01 15:41:14 +01005470 if (needs_write_barrier) {
5471 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005472 locations->AddTemp(Location::RequiresRegister());
Calin Juravle34166012014-12-19 17:22:29 +00005473 } else if (generate_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005474 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005475 // - registers need to be consecutive
5476 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005477 // We don't test for ARM yet, and the assertion makes sure that we
5478 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005479 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5480
5481 locations->AddTemp(Location::RequiresRegister());
5482 locations->AddTemp(Location::RequiresRegister());
5483 if (field_type == Primitive::kPrimDouble) {
5484 // For doubles we need two more registers to copy the value.
5485 locations->AddTemp(Location::RegisterLocation(R2));
5486 locations->AddTemp(Location::RegisterLocation(R3));
5487 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01005488 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005489}
5490
Calin Juravle52c48962014-12-16 17:02:57 +00005491void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005492 const FieldInfo& field_info,
5493 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00005494 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
5495
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005496 LocationSummary* locations = instruction->GetLocations();
Calin Juravle52c48962014-12-16 17:02:57 +00005497 Register base = locations->InAt(0).AsRegister<Register>();
5498 Location value = locations->InAt(1);
5499
5500 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005501 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005502 Primitive::Type field_type = field_info.GetFieldType();
5503 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01005504 bool needs_write_barrier =
5505 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00005506
5507 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005508 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
Calin Juravle52c48962014-12-16 17:02:57 +00005509 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005510
5511 switch (field_type) {
5512 case Primitive::kPrimBoolean:
5513 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00005514 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005515 break;
5516 }
5517
5518 case Primitive::kPrimShort:
5519 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00005520 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005521 break;
5522 }
5523
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01005524 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005525 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01005526 if (kPoisonHeapReferences && needs_write_barrier) {
5527 // Note that in the case where `value` is a null reference,
5528 // we do not enter this block, as a null reference does not
5529 // need poisoning.
5530 DCHECK_EQ(field_type, Primitive::kPrimNot);
5531 Register temp = locations->GetTemp(0).AsRegister<Register>();
5532 __ Mov(temp, value.AsRegister<Register>());
5533 __ PoisonHeapReference(temp);
5534 __ StoreToOffset(kStoreWord, temp, base, offset);
5535 } else {
5536 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
5537 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005538 break;
5539 }
5540
5541 case Primitive::kPrimLong: {
Calin Juravle34166012014-12-19 17:22:29 +00005542 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005543 GenerateWideAtomicStore(base, offset,
5544 value.AsRegisterPairLow<Register>(),
5545 value.AsRegisterPairHigh<Register>(),
5546 locations->GetTemp(0).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005547 locations->GetTemp(1).AsRegister<Register>(),
5548 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005549 } else {
5550 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005551 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005552 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005553 break;
5554 }
5555
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005556 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00005557 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005558 break;
5559 }
5560
5561 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005562 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005563 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005564 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>();
5565 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>();
5566
5567 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg);
5568
5569 GenerateWideAtomicStore(base, offset,
5570 value_reg_lo,
5571 value_reg_hi,
5572 locations->GetTemp(2).AsRegister<Register>(),
Calin Juravle77520bc2015-01-12 18:45:46 +00005573 locations->GetTemp(3).AsRegister<Register>(),
5574 instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005575 } else {
5576 __ StoreDToOffset(value_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005577 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005578 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005579 break;
5580 }
5581
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005582 case Primitive::kPrimVoid:
5583 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005584 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005585 }
Calin Juravle52c48962014-12-16 17:02:57 +00005586
Calin Juravle77520bc2015-01-12 18:45:46 +00005587 // Longs and doubles are handled in the switch.
5588 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) {
5589 codegen_->MaybeRecordImplicitNullCheck(instruction);
5590 }
5591
5592 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
5593 Register temp = locations->GetTemp(0).AsRegister<Register>();
5594 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005595 codegen_->MarkGCCard(
5596 temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00005597 }
5598
Calin Juravle52c48962014-12-16 17:02:57 +00005599 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005600 codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
Calin Juravle52c48962014-12-16 17:02:57 +00005601 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005602}
5603
Calin Juravle52c48962014-12-16 17:02:57 +00005604void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
5605 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Roland Levillain3b359c72015-11-17 19:35:12 +00005606
5607 bool object_field_get_with_read_barrier =
5608 kEmitCompilerReadBarrier && (field_info.GetFieldType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01005609 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00005610 new (GetGraph()->GetArena()) LocationSummary(instruction,
5611 object_field_get_with_read_barrier ?
5612 LocationSummary::kCallOnSlowPath :
5613 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01005614 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005615 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01005616 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01005617 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00005618
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005619 bool volatile_for_double = field_info.IsVolatile()
Calin Juravle34166012014-12-19 17:22:29 +00005620 && (field_info.GetFieldType() == Primitive::kPrimDouble)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005621 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Roland Levillain3b359c72015-11-17 19:35:12 +00005622 // The output overlaps in case of volatile long: we don't want the
5623 // code generated by GenerateWideAtomicLoad to overwrite the
5624 // object's location. Likewise, in the case of an object field get
5625 // with read barriers enabled, we do not want the load to overwrite
5626 // the object's location, as we need it to emit the read barrier.
5627 bool overlap = (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) ||
5628 object_field_get_with_read_barrier;
Nicolas Geoffrayacc0b8e2015-04-20 12:39:57 +01005629
Alexandre Rames88c13cd2015-04-14 17:35:39 +01005630 if (Primitive::IsFloatingPointType(instruction->GetType())) {
5631 locations->SetOut(Location::RequiresFpuRegister());
5632 } else {
5633 locations->SetOut(Location::RequiresRegister(),
5634 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap));
5635 }
Nicolas Geoffray829280c2015-01-28 10:20:37 +00005636 if (volatile_for_double) {
Roland Levillainc9285912015-12-18 10:38:42 +00005637 // ARM encoding have some additional constraints for ldrexd/strexd:
Calin Juravle52c48962014-12-16 17:02:57 +00005638 // - registers need to be consecutive
5639 // - the first register should be even but not R14.
Roland Levillainc9285912015-12-18 10:38:42 +00005640 // We don't test for ARM yet, and the assertion makes sure that we
5641 // revisit this if we ever enable ARM encoding.
Calin Juravle52c48962014-12-16 17:02:57 +00005642 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet());
5643 locations->AddTemp(Location::RequiresRegister());
5644 locations->AddTemp(Location::RequiresRegister());
Roland Levillainc9285912015-12-18 10:38:42 +00005645 } else if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
5646 // We need a temporary register for the read barrier marking slow
5647 // path in CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
5648 locations->AddTemp(Location::RequiresRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00005649 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005650}
5651
Vladimir Marko37dd80d2016-08-01 17:41:45 +01005652Location LocationsBuilderARM::ArithmeticZeroOrFpuRegister(HInstruction* input) {
5653 DCHECK(input->GetType() == Primitive::kPrimDouble || input->GetType() == Primitive::kPrimFloat)
5654 << input->GetType();
5655 if ((input->IsFloatConstant() && (input->AsFloatConstant()->IsArithmeticZero())) ||
5656 (input->IsDoubleConstant() && (input->AsDoubleConstant()->IsArithmeticZero()))) {
5657 return Location::ConstantLocation(input->AsConstant());
5658 } else {
5659 return Location::RequiresFpuRegister();
5660 }
5661}
5662
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005663Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
5664 Opcode opcode) {
5665 DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
5666 if (constant->IsConstant() &&
5667 CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
5668 return Location::ConstantLocation(constant->AsConstant());
5669 }
5670 return Location::RequiresRegister();
5671}
5672
5673bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
5674 Opcode opcode) {
5675 uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
5676 if (Primitive::Is64BitType(input_cst->GetType())) {
Vladimir Marko59751a72016-08-05 14:37:27 +01005677 Opcode high_opcode = opcode;
5678 SetCc low_set_cc = kCcDontCare;
5679 switch (opcode) {
5680 case SUB:
5681 // Flip the operation to an ADD.
5682 value = -value;
5683 opcode = ADD;
5684 FALLTHROUGH_INTENDED;
5685 case ADD:
5686 if (Low32Bits(value) == 0u) {
5687 return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare);
5688 }
5689 high_opcode = ADC;
5690 low_set_cc = kCcSet;
5691 break;
5692 default:
5693 break;
5694 }
5695 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) &&
5696 CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005697 } else {
5698 return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
5699 }
5700}
5701
Vladimir Marko59751a72016-08-05 14:37:27 +01005702bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value,
5703 Opcode opcode,
5704 SetCc set_cc) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005705 ShifterOperand so;
5706 ArmAssembler* assembler = codegen_->GetAssembler();
Vladimir Marko59751a72016-08-05 14:37:27 +01005707 if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, set_cc, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005708 return true;
5709 }
5710 Opcode neg_opcode = kNoOperand;
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005711 uint32_t neg_value = 0;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005712 switch (opcode) {
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005713 case AND: neg_opcode = BIC; neg_value = ~value; break;
5714 case ORR: neg_opcode = ORN; neg_value = ~value; break;
5715 case ADD: neg_opcode = SUB; neg_value = -value; break;
5716 case ADC: neg_opcode = SBC; neg_value = ~value; break;
5717 case SUB: neg_opcode = ADD; neg_value = -value; break;
5718 case SBC: neg_opcode = ADC; neg_value = ~value; break;
5719 case MOV: neg_opcode = MVN; neg_value = ~value; break;
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005720 default:
5721 return false;
5722 }
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00005723
5724 if (assembler->ShifterOperandCanHold(kNoRegister,
5725 kNoRegister,
5726 neg_opcode,
5727 neg_value,
5728 set_cc,
5729 &so)) {
5730 return true;
5731 }
5732
5733 return opcode == AND && IsPowerOfTwo(value + 1);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01005734}
5735
Calin Juravle52c48962014-12-16 17:02:57 +00005736void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
5737 const FieldInfo& field_info) {
5738 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005739
Calin Juravle52c48962014-12-16 17:02:57 +00005740 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00005741 Location base_loc = locations->InAt(0);
5742 Register base = base_loc.AsRegister<Register>();
Calin Juravle52c48962014-12-16 17:02:57 +00005743 Location out = locations->Out();
5744 bool is_volatile = field_info.IsVolatile();
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005745 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
Calin Juravle52c48962014-12-16 17:02:57 +00005746 Primitive::Type field_type = field_info.GetFieldType();
5747 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
5748
5749 switch (field_type) {
Roland Levillainc9285912015-12-18 10:38:42 +00005750 case Primitive::kPrimBoolean:
Calin Juravle52c48962014-12-16 17:02:57 +00005751 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005752 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005753
Roland Levillainc9285912015-12-18 10:38:42 +00005754 case Primitive::kPrimByte:
Calin Juravle52c48962014-12-16 17:02:57 +00005755 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005756 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005757
Roland Levillainc9285912015-12-18 10:38:42 +00005758 case Primitive::kPrimShort:
Calin Juravle52c48962014-12-16 17:02:57 +00005759 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005760 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005761
Roland Levillainc9285912015-12-18 10:38:42 +00005762 case Primitive::kPrimChar:
Calin Juravle52c48962014-12-16 17:02:57 +00005763 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005764 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005765
5766 case Primitive::kPrimInt:
Calin Juravle52c48962014-12-16 17:02:57 +00005767 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005768 break;
Roland Levillainc9285912015-12-18 10:38:42 +00005769
5770 case Primitive::kPrimNot: {
5771 // /* HeapReference<Object> */ out = *(base + offset)
5772 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
5773 Location temp_loc = locations->GetTemp(0);
5774 // Note that a potential implicit null check is handled in this
5775 // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier call.
5776 codegen_->GenerateFieldLoadWithBakerReadBarrier(
5777 instruction, out, base, offset, temp_loc, /* needs_null_check */ true);
5778 if (is_volatile) {
5779 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5780 }
5781 } else {
5782 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset);
5783 codegen_->MaybeRecordImplicitNullCheck(instruction);
5784 if (is_volatile) {
5785 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5786 }
5787 // If read barriers are enabled, emit read barriers other than
5788 // Baker's using a slow path (and also unpoison the loaded
5789 // reference, if heap poisoning is enabled).
5790 codegen_->MaybeGenerateReadBarrierSlow(instruction, out, out, base_loc, offset);
5791 }
5792 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005793 }
5794
Roland Levillainc9285912015-12-18 10:38:42 +00005795 case Primitive::kPrimLong:
Calin Juravle34166012014-12-19 17:22:29 +00005796 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005797 GenerateWideAtomicLoad(base, offset,
5798 out.AsRegisterPairLow<Register>(),
5799 out.AsRegisterPairHigh<Register>());
5800 } else {
5801 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset);
5802 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005803 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005804
Roland Levillainc9285912015-12-18 10:38:42 +00005805 case Primitive::kPrimFloat:
Calin Juravle52c48962014-12-16 17:02:57 +00005806 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset);
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005807 break;
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005808
5809 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00005810 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>());
Calin Juravle34166012014-12-19 17:22:29 +00005811 if (is_volatile && !atomic_ldrd_strd) {
Calin Juravle52c48962014-12-16 17:02:57 +00005812 Register lo = locations->GetTemp(0).AsRegister<Register>();
5813 Register hi = locations->GetTemp(1).AsRegister<Register>();
5814 GenerateWideAtomicLoad(base, offset, lo, hi);
Calin Juravle77520bc2015-01-12 18:45:46 +00005815 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005816 __ vmovdrr(out_reg, lo, hi);
5817 } else {
5818 __ LoadDFromOffset(out_reg, base, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00005819 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00005820 }
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00005821 break;
5822 }
5823
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005824 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00005825 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07005826 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005827 }
Calin Juravle52c48962014-12-16 17:02:57 +00005828
Roland Levillainc9285912015-12-18 10:38:42 +00005829 if (field_type == Primitive::kPrimNot || field_type == Primitive::kPrimDouble) {
5830 // Potential implicit null checks, in the case of reference or
5831 // double fields, are handled in the previous switch statement.
5832 } else {
Calin Juravle77520bc2015-01-12 18:45:46 +00005833 codegen_->MaybeRecordImplicitNullCheck(instruction);
5834 }
5835
Calin Juravle52c48962014-12-16 17:02:57 +00005836 if (is_volatile) {
Roland Levillainc9285912015-12-18 10:38:42 +00005837 if (field_type == Primitive::kPrimNot) {
5838 // Memory barriers, in the case of references, are also handled
5839 // in the previous switch statement.
5840 } else {
5841 codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
5842 }
Roland Levillain4d027112015-07-01 15:41:14 +01005843 }
Calin Juravle52c48962014-12-16 17:02:57 +00005844}
5845
5846void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
5847 HandleFieldSet(instruction, instruction->GetFieldInfo());
5848}
5849
5850void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005851 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00005852}
5853
5854void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5855 HandleFieldGet(instruction, instruction->GetFieldInfo());
5856}
5857
5858void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5859 HandleFieldGet(instruction, instruction->GetFieldInfo());
5860}
5861
5862void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5863 HandleFieldGet(instruction, instruction->GetFieldInfo());
5864}
5865
5866void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5867 HandleFieldGet(instruction, instruction->GetFieldInfo());
5868}
5869
5870void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5871 HandleFieldSet(instruction, instruction->GetFieldInfo());
5872}
5873
5874void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01005875 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005876}
5877
Calin Juravlee460d1d2015-09-29 04:52:17 +01005878void LocationsBuilderARM::VisitUnresolvedInstanceFieldGet(
5879 HUnresolvedInstanceFieldGet* instruction) {
5880 FieldAccessCallingConventionARM calling_convention;
5881 codegen_->CreateUnresolvedFieldLocationSummary(
5882 instruction, instruction->GetFieldType(), calling_convention);
5883}
5884
5885void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldGet(
5886 HUnresolvedInstanceFieldGet* instruction) {
5887 FieldAccessCallingConventionARM calling_convention;
5888 codegen_->GenerateUnresolvedFieldAccess(instruction,
5889 instruction->GetFieldType(),
5890 instruction->GetFieldIndex(),
5891 instruction->GetDexPc(),
5892 calling_convention);
5893}
5894
5895void LocationsBuilderARM::VisitUnresolvedInstanceFieldSet(
5896 HUnresolvedInstanceFieldSet* instruction) {
5897 FieldAccessCallingConventionARM calling_convention;
5898 codegen_->CreateUnresolvedFieldLocationSummary(
5899 instruction, instruction->GetFieldType(), calling_convention);
5900}
5901
5902void InstructionCodeGeneratorARM::VisitUnresolvedInstanceFieldSet(
5903 HUnresolvedInstanceFieldSet* instruction) {
5904 FieldAccessCallingConventionARM calling_convention;
5905 codegen_->GenerateUnresolvedFieldAccess(instruction,
5906 instruction->GetFieldType(),
5907 instruction->GetFieldIndex(),
5908 instruction->GetDexPc(),
5909 calling_convention);
5910}
5911
5912void LocationsBuilderARM::VisitUnresolvedStaticFieldGet(
5913 HUnresolvedStaticFieldGet* instruction) {
5914 FieldAccessCallingConventionARM calling_convention;
5915 codegen_->CreateUnresolvedFieldLocationSummary(
5916 instruction, instruction->GetFieldType(), calling_convention);
5917}
5918
5919void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldGet(
5920 HUnresolvedStaticFieldGet* instruction) {
5921 FieldAccessCallingConventionARM calling_convention;
5922 codegen_->GenerateUnresolvedFieldAccess(instruction,
5923 instruction->GetFieldType(),
5924 instruction->GetFieldIndex(),
5925 instruction->GetDexPc(),
5926 calling_convention);
5927}
5928
5929void LocationsBuilderARM::VisitUnresolvedStaticFieldSet(
5930 HUnresolvedStaticFieldSet* instruction) {
5931 FieldAccessCallingConventionARM calling_convention;
5932 codegen_->CreateUnresolvedFieldLocationSummary(
5933 instruction, instruction->GetFieldType(), calling_convention);
5934}
5935
5936void InstructionCodeGeneratorARM::VisitUnresolvedStaticFieldSet(
5937 HUnresolvedStaticFieldSet* instruction) {
5938 FieldAccessCallingConventionARM calling_convention;
5939 codegen_->GenerateUnresolvedFieldAccess(instruction,
5940 instruction->GetFieldType(),
5941 instruction->GetFieldIndex(),
5942 instruction->GetDexPc(),
5943 calling_convention);
5944}
5945
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005946void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005947 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
5948 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005949}
5950
Calin Juravle2ae48182016-03-16 14:05:09 +00005951void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
5952 if (CanMoveNullCheckToUser(instruction)) {
Calin Juravle77520bc2015-01-12 18:45:46 +00005953 return;
5954 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005955 Location obj = instruction->GetLocations()->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00005956
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005957 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00005958 RecordPcInfo(instruction, instruction->GetDexPc());
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005959}
5960
Calin Juravle2ae48182016-03-16 14:05:09 +00005961void CodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) {
Artem Serovf4d6aee2016-07-11 10:41:45 +01005962 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00005963 AddSlowPath(slow_path);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005964
5965 LocationSummary* locations = instruction->GetLocations();
5966 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005967
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01005968 __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01005969}
5970
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005971void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00005972 codegen_->GenerateNullCheck(instruction);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00005973}
5974
Artem Serov6c916792016-07-11 14:02:34 +01005975static LoadOperandType GetLoadOperandType(Primitive::Type type) {
5976 switch (type) {
5977 case Primitive::kPrimNot:
5978 return kLoadWord;
5979 case Primitive::kPrimBoolean:
5980 return kLoadUnsignedByte;
5981 case Primitive::kPrimByte:
5982 return kLoadSignedByte;
5983 case Primitive::kPrimChar:
5984 return kLoadUnsignedHalfword;
5985 case Primitive::kPrimShort:
5986 return kLoadSignedHalfword;
5987 case Primitive::kPrimInt:
5988 return kLoadWord;
5989 case Primitive::kPrimLong:
5990 return kLoadWordPair;
5991 case Primitive::kPrimFloat:
5992 return kLoadSWord;
5993 case Primitive::kPrimDouble:
5994 return kLoadDWord;
5995 default:
5996 LOG(FATAL) << "Unreachable type " << type;
5997 UNREACHABLE();
5998 }
5999}
6000
6001static StoreOperandType GetStoreOperandType(Primitive::Type type) {
6002 switch (type) {
6003 case Primitive::kPrimNot:
6004 return kStoreWord;
6005 case Primitive::kPrimBoolean:
6006 case Primitive::kPrimByte:
6007 return kStoreByte;
6008 case Primitive::kPrimChar:
6009 case Primitive::kPrimShort:
6010 return kStoreHalfword;
6011 case Primitive::kPrimInt:
6012 return kStoreWord;
6013 case Primitive::kPrimLong:
6014 return kStoreWordPair;
6015 case Primitive::kPrimFloat:
6016 return kStoreSWord;
6017 case Primitive::kPrimDouble:
6018 return kStoreDWord;
6019 default:
6020 LOG(FATAL) << "Unreachable type " << type;
6021 UNREACHABLE();
6022 }
6023}
6024
6025void CodeGeneratorARM::LoadFromShiftedRegOffset(Primitive::Type type,
6026 Location out_loc,
6027 Register base,
6028 Register reg_offset,
6029 Condition cond) {
6030 uint32_t shift_count = Primitive::ComponentSizeShift(type);
6031 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
6032
6033 switch (type) {
6034 case Primitive::kPrimByte:
6035 __ ldrsb(out_loc.AsRegister<Register>(), mem_address, cond);
6036 break;
6037 case Primitive::kPrimBoolean:
6038 __ ldrb(out_loc.AsRegister<Register>(), mem_address, cond);
6039 break;
6040 case Primitive::kPrimShort:
6041 __ ldrsh(out_loc.AsRegister<Register>(), mem_address, cond);
6042 break;
6043 case Primitive::kPrimChar:
6044 __ ldrh(out_loc.AsRegister<Register>(), mem_address, cond);
6045 break;
6046 case Primitive::kPrimNot:
6047 case Primitive::kPrimInt:
6048 __ ldr(out_loc.AsRegister<Register>(), mem_address, cond);
6049 break;
6050 // T32 doesn't support LoadFromShiftedRegOffset mem address mode for these types.
6051 case Primitive::kPrimLong:
6052 case Primitive::kPrimFloat:
6053 case Primitive::kPrimDouble:
6054 default:
6055 LOG(FATAL) << "Unreachable type " << type;
6056 UNREACHABLE();
6057 }
6058}
6059
6060void CodeGeneratorARM::StoreToShiftedRegOffset(Primitive::Type type,
6061 Location loc,
6062 Register base,
6063 Register reg_offset,
6064 Condition cond) {
6065 uint32_t shift_count = Primitive::ComponentSizeShift(type);
6066 Address mem_address(base, reg_offset, Shift::LSL, shift_count);
6067
6068 switch (type) {
6069 case Primitive::kPrimByte:
6070 case Primitive::kPrimBoolean:
6071 __ strb(loc.AsRegister<Register>(), mem_address, cond);
6072 break;
6073 case Primitive::kPrimShort:
6074 case Primitive::kPrimChar:
6075 __ strh(loc.AsRegister<Register>(), mem_address, cond);
6076 break;
6077 case Primitive::kPrimNot:
6078 case Primitive::kPrimInt:
6079 __ str(loc.AsRegister<Register>(), mem_address, cond);
6080 break;
6081 // T32 doesn't support StoreToShiftedRegOffset mem address mode for these types.
6082 case Primitive::kPrimLong:
6083 case Primitive::kPrimFloat:
6084 case Primitive::kPrimDouble:
6085 default:
6086 LOG(FATAL) << "Unreachable type " << type;
6087 UNREACHABLE();
6088 }
6089}
6090
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006091void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
Roland Levillain3b359c72015-11-17 19:35:12 +00006092 bool object_array_get_with_read_barrier =
6093 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot);
Nicolas Geoffray39468442014-09-02 15:17:15 +01006094 LocationSummary* locations =
Roland Levillain3b359c72015-11-17 19:35:12 +00006095 new (GetGraph()->GetArena()) LocationSummary(instruction,
6096 object_array_get_with_read_barrier ?
6097 LocationSummary::kCallOnSlowPath :
6098 LocationSummary::kNoCall);
Vladimir Marko70e97462016-08-09 11:04:26 +01006099 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006100 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01006101 }
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006102 locations->SetInAt(0, Location::RequiresRegister());
6103 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01006104 if (Primitive::IsFloatingPointType(instruction->GetType())) {
6105 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6106 } else {
Roland Levillain3b359c72015-11-17 19:35:12 +00006107 // The output overlaps in the case of an object array get with
6108 // read barriers enabled: we do not want the move to overwrite the
6109 // array's location, as we need it to emit the read barrier.
6110 locations->SetOut(
6111 Location::RequiresRegister(),
6112 object_array_get_with_read_barrier ? Location::kOutputOverlap : Location::kNoOutputOverlap);
Alexandre Rames88c13cd2015-04-14 17:35:39 +01006113 }
Roland Levillainc9285912015-12-18 10:38:42 +00006114 // We need a temporary register for the read barrier marking slow
6115 // path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
jessicahandojo05765752016-09-09 19:01:32 -07006116 // Also need for String compression feature.
6117 if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
6118 || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
Roland Levillainc9285912015-12-18 10:38:42 +00006119 locations->AddTemp(Location::RequiresRegister());
6120 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006121}
6122
6123void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
6124 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006125 Location obj_loc = locations->InAt(0);
6126 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006127 Location index = locations->InAt(1);
Roland Levillainc9285912015-12-18 10:38:42 +00006128 Location out_loc = locations->Out();
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01006129 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Roland Levillainc9285912015-12-18 10:38:42 +00006130 Primitive::Type type = instruction->GetType();
jessicahandojo05765752016-09-09 19:01:32 -07006131 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
6132 instruction->IsStringCharAt();
Artem Serov328429f2016-07-06 16:23:04 +01006133 HInstruction* array_instr = instruction->GetArray();
6134 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Artem Serov6c916792016-07-11 14:02:34 +01006135
Roland Levillain4d027112015-07-01 15:41:14 +01006136 switch (type) {
Artem Serov6c916792016-07-11 14:02:34 +01006137 case Primitive::kPrimBoolean:
6138 case Primitive::kPrimByte:
6139 case Primitive::kPrimShort:
6140 case Primitive::kPrimChar:
Roland Levillainc9285912015-12-18 10:38:42 +00006141 case Primitive::kPrimInt: {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006142 Register length;
6143 if (maybe_compressed_char_at) {
6144 length = locations->GetTemp(0).AsRegister<Register>();
6145 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
6146 __ LoadFromOffset(kLoadWord, length, obj, count_offset);
6147 codegen_->MaybeRecordImplicitNullCheck(instruction);
6148 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006149 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01006150 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
jessicahandojo05765752016-09-09 19:01:32 -07006151 if (maybe_compressed_char_at) {
jessicahandojo05765752016-09-09 19:01:32 -07006152 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006153 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006154 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
6155 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
6156 "Expecting 0=compressed, 1=uncompressed");
6157 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07006158 __ LoadFromOffset(kLoadUnsignedByte,
6159 out_loc.AsRegister<Register>(),
6160 obj,
6161 data_offset + const_index);
Anton Kirilov6f644202017-02-27 18:29:45 +00006162 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07006163 __ Bind(&uncompressed_load);
6164 __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
6165 out_loc.AsRegister<Register>(),
6166 obj,
6167 data_offset + (const_index << 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00006168 if (done.IsLinked()) {
6169 __ Bind(&done);
6170 }
jessicahandojo05765752016-09-09 19:01:32 -07006171 } else {
6172 uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
Artem Serov6c916792016-07-11 14:02:34 +01006173
jessicahandojo05765752016-09-09 19:01:32 -07006174 LoadOperandType load_type = GetLoadOperandType(type);
6175 __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
6176 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006177 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006178 Register temp = IP;
6179
6180 if (has_intermediate_address) {
6181 // We do not need to compute the intermediate address from the array: the
6182 // input instruction has done it already. See the comment in
6183 // `TryExtractArrayAccessAddress()`.
6184 if (kIsDebugBuild) {
6185 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6186 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
6187 }
6188 temp = obj;
6189 } else {
6190 __ add(temp, obj, ShifterOperand(data_offset));
6191 }
jessicahandojo05765752016-09-09 19:01:32 -07006192 if (maybe_compressed_char_at) {
6193 Label uncompressed_load, done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006194 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006195 __ Lsrs(length, length, 1u); // LSRS has a 16-bit encoding, TST (immediate) does not.
6196 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
6197 "Expecting 0=compressed, 1=uncompressed");
6198 __ b(&uncompressed_load, CS);
jessicahandojo05765752016-09-09 19:01:32 -07006199 __ ldrb(out_loc.AsRegister<Register>(),
6200 Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
Anton Kirilov6f644202017-02-27 18:29:45 +00006201 __ b(final_label);
jessicahandojo05765752016-09-09 19:01:32 -07006202 __ Bind(&uncompressed_load);
6203 __ ldrh(out_loc.AsRegister<Register>(),
6204 Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
Anton Kirilov6f644202017-02-27 18:29:45 +00006205 if (done.IsLinked()) {
6206 __ Bind(&done);
6207 }
jessicahandojo05765752016-09-09 19:01:32 -07006208 } else {
6209 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
6210 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006211 }
6212 break;
6213 }
6214
Roland Levillainc9285912015-12-18 10:38:42 +00006215 case Primitive::kPrimNot: {
Roland Levillain19c54192016-11-04 13:44:09 +00006216 // The read barrier instrumentation of object ArrayGet
6217 // instructions does not support the HIntermediateAddress
6218 // instruction.
6219 DCHECK(!(has_intermediate_address && kEmitCompilerReadBarrier));
6220
Roland Levillainc9285912015-12-18 10:38:42 +00006221 static_assert(
6222 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6223 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00006224 // /* HeapReference<Object> */ out =
6225 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
6226 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
6227 Location temp = locations->GetTemp(0);
6228 // Note that a potential implicit null check is handled in this
6229 // CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier call.
6230 codegen_->GenerateArrayLoadWithBakerReadBarrier(
6231 instruction, out_loc, obj, data_offset, index, temp, /* needs_null_check */ true);
6232 } else {
6233 Register out = out_loc.AsRegister<Register>();
6234 if (index.IsConstant()) {
6235 size_t offset =
6236 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6237 __ LoadFromOffset(kLoadWord, out, obj, offset);
6238 codegen_->MaybeRecordImplicitNullCheck(instruction);
6239 // If read barriers are enabled, emit read barriers other than
6240 // Baker's using a slow path (and also unpoison the loaded
6241 // reference, if heap poisoning is enabled).
6242 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
6243 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006244 Register temp = IP;
6245
6246 if (has_intermediate_address) {
6247 // We do not need to compute the intermediate address from the array: the
6248 // input instruction has done it already. See the comment in
6249 // `TryExtractArrayAccessAddress()`.
6250 if (kIsDebugBuild) {
6251 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6252 DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
6253 }
6254 temp = obj;
6255 } else {
6256 __ add(temp, obj, ShifterOperand(data_offset));
6257 }
6258 codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
Artem Serov6c916792016-07-11 14:02:34 +01006259
Roland Levillainc9285912015-12-18 10:38:42 +00006260 codegen_->MaybeRecordImplicitNullCheck(instruction);
6261 // If read barriers are enabled, emit read barriers other than
6262 // Baker's using a slow path (and also unpoison the loaded
6263 // reference, if heap poisoning is enabled).
6264 codegen_->MaybeGenerateReadBarrierSlow(
6265 instruction, out_loc, out_loc, obj_loc, data_offset, index);
6266 }
6267 }
6268 break;
6269 }
6270
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006271 case Primitive::kPrimLong: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006272 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006273 size_t offset =
6274 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006275 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), obj, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006276 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006277 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00006278 __ LoadFromOffset(kLoadWordPair, out_loc.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006279 }
6280 break;
6281 }
6282
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006283 case Primitive::kPrimFloat: {
Roland Levillainc9285912015-12-18 10:38:42 +00006284 SRegister out = out_loc.AsFpuRegister<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006285 if (index.IsConstant()) {
6286 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006287 __ LoadSFromOffset(out, obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006288 } else {
6289 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Roland Levillainc9285912015-12-18 10:38:42 +00006290 __ LoadSFromOffset(out, IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006291 }
6292 break;
6293 }
6294
6295 case Primitive::kPrimDouble: {
Roland Levillainc9285912015-12-18 10:38:42 +00006296 SRegister out = out_loc.AsFpuRegisterPairLow<SRegister>();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006297 if (index.IsConstant()) {
6298 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Roland Levillainc9285912015-12-18 10:38:42 +00006299 __ LoadDFromOffset(FromLowSToD(out), obj, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006300 } else {
6301 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Roland Levillainc9285912015-12-18 10:38:42 +00006302 __ LoadDFromOffset(FromLowSToD(out), IP, data_offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006303 }
6304 break;
6305 }
6306
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006307 case Primitive::kPrimVoid:
Roland Levillain4d027112015-07-01 15:41:14 +01006308 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07006309 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006310 }
Roland Levillain4d027112015-07-01 15:41:14 +01006311
6312 if (type == Primitive::kPrimNot) {
Roland Levillainc9285912015-12-18 10:38:42 +00006313 // Potential implicit null checks, in the case of reference
6314 // arrays, are handled in the previous switch statement.
jessicahandojo05765752016-09-09 19:01:32 -07006315 } else if (!maybe_compressed_char_at) {
Roland Levillainc9285912015-12-18 10:38:42 +00006316 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain4d027112015-07-01 15:41:14 +01006317 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006318}
6319
6320void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01006321 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006322
6323 bool needs_write_barrier =
6324 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Roland Levillain3b359c72015-11-17 19:35:12 +00006325 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006326
Nicolas Geoffray39468442014-09-02 15:17:15 +01006327 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006328 instruction,
Vladimir Marko8d49fd72016-08-25 15:20:47 +01006329 may_need_runtime_call_for_type_check ?
Roland Levillain3b359c72015-11-17 19:35:12 +00006330 LocationSummary::kCallOnSlowPath :
6331 LocationSummary::kNoCall);
6332
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006333 locations->SetInAt(0, Location::RequiresRegister());
6334 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
6335 if (Primitive::IsFloatingPointType(value_type)) {
6336 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006337 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006338 locations->SetInAt(2, Location::RequiresRegister());
6339 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006340 if (needs_write_barrier) {
6341 // Temporary registers for the write barrier.
6342 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Roland Levillain4f6b0b52015-11-23 19:29:22 +00006343 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006344 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006345}
6346
6347void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
6348 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00006349 Location array_loc = locations->InAt(0);
6350 Register array = array_loc.AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006351 Location index = locations->InAt(1);
Nicolas Geoffray39468442014-09-02 15:17:15 +01006352 Primitive::Type value_type = instruction->GetComponentType();
Roland Levillain3b359c72015-11-17 19:35:12 +00006353 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006354 bool needs_write_barrier =
6355 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Artem Serov6c916792016-07-11 14:02:34 +01006356 uint32_t data_offset =
6357 mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
6358 Location value_loc = locations->InAt(2);
Artem Serov328429f2016-07-06 16:23:04 +01006359 HInstruction* array_instr = instruction->GetArray();
6360 bool has_intermediate_address = array_instr->IsIntermediateAddress();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006361
6362 switch (value_type) {
6363 case Primitive::kPrimBoolean:
Artem Serov6c916792016-07-11 14:02:34 +01006364 case Primitive::kPrimByte:
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006365 case Primitive::kPrimShort:
Artem Serov6c916792016-07-11 14:02:34 +01006366 case Primitive::kPrimChar:
6367 case Primitive::kPrimInt: {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006368 if (index.IsConstant()) {
Artem Serov6c916792016-07-11 14:02:34 +01006369 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
6370 uint32_t full_offset =
6371 data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
6372 StoreOperandType store_type = GetStoreOperandType(value_type);
6373 __ StoreToOffset(store_type, value_loc.AsRegister<Register>(), array, full_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006374 } else {
Artem Serov328429f2016-07-06 16:23:04 +01006375 Register temp = IP;
6376
6377 if (has_intermediate_address) {
6378 // We do not need to compute the intermediate address from the array: the
6379 // input instruction has done it already. See the comment in
6380 // `TryExtractArrayAccessAddress()`.
6381 if (kIsDebugBuild) {
6382 HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
6383 DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
6384 }
6385 temp = array;
6386 } else {
6387 __ add(temp, array, ShifterOperand(data_offset));
6388 }
Artem Serov6c916792016-07-11 14:02:34 +01006389 codegen_->StoreToShiftedRegOffset(value_type,
6390 value_loc,
Artem Serov328429f2016-07-06 16:23:04 +01006391 temp,
Artem Serov6c916792016-07-11 14:02:34 +01006392 index.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006393 }
6394 break;
6395 }
6396
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006397 case Primitive::kPrimNot: {
Roland Levillain3b359c72015-11-17 19:35:12 +00006398 Register value = value_loc.AsRegister<Register>();
Artem Serov328429f2016-07-06 16:23:04 +01006399 // TryExtractArrayAccessAddress optimization is never applied for non-primitive ArraySet.
6400 // See the comment in instruction_simplifier_shared.cc.
6401 DCHECK(!has_intermediate_address);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006402
6403 if (instruction->InputAt(2)->IsNullConstant()) {
6404 // Just setting null.
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006405 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006406 size_t offset =
6407 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Artem Serov6c916792016-07-11 14:02:34 +01006408 __ StoreToOffset(kStoreWord, value, array, offset);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006409 } else {
6410 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006411 __ add(IP, array, ShifterOperand(data_offset));
6412 codegen_->StoreToShiftedRegOffset(value_type,
6413 value_loc,
6414 IP,
6415 index.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006416 }
Roland Levillain1407ee72016-01-08 15:56:19 +00006417 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain3b359c72015-11-17 19:35:12 +00006418 DCHECK(!needs_write_barrier);
6419 DCHECK(!may_need_runtime_call_for_type_check);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006420 break;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00006421 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006422
6423 DCHECK(needs_write_barrier);
Roland Levillain16d9f942016-08-25 17:27:56 +01006424 Location temp1_loc = locations->GetTemp(0);
6425 Register temp1 = temp1_loc.AsRegister<Register>();
6426 Location temp2_loc = locations->GetTemp(1);
6427 Register temp2 = temp2_loc.AsRegister<Register>();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006428 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
6429 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
6430 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
6431 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00006432 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01006433 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006434
Roland Levillain3b359c72015-11-17 19:35:12 +00006435 if (may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006436 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathARM(instruction);
6437 codegen_->AddSlowPath(slow_path);
6438 if (instruction->GetValueCanBeNull()) {
6439 Label non_zero;
6440 __ CompareAndBranchIfNonZero(value, &non_zero);
6441 if (index.IsConstant()) {
6442 size_t offset =
6443 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6444 __ StoreToOffset(kStoreWord, value, array, offset);
6445 } else {
6446 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006447 __ add(IP, array, ShifterOperand(data_offset));
6448 codegen_->StoreToShiftedRegOffset(value_type,
6449 value_loc,
6450 IP,
6451 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006452 }
6453 codegen_->MaybeRecordImplicitNullCheck(instruction);
Anton Kirilov6f644202017-02-27 18:29:45 +00006454 __ b(final_label);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006455 __ Bind(&non_zero);
6456 }
6457
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006458 // Note that when read barriers are enabled, the type checks
6459 // are performed without read barriers. This is fine, even in
6460 // the case where a class object is in the from-space after
6461 // the flip, as a comparison involving such a type would not
6462 // produce a false positive; it may of course produce a false
6463 // negative, in which case we would take the ArraySet slow
6464 // path.
Roland Levillain16d9f942016-08-25 17:27:56 +01006465
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006466 // /* HeapReference<Class> */ temp1 = array->klass_
6467 __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
6468 codegen_->MaybeRecordImplicitNullCheck(instruction);
6469 __ MaybeUnpoisonHeapReference(temp1);
Roland Levillain16d9f942016-08-25 17:27:56 +01006470
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006471 // /* HeapReference<Class> */ temp1 = temp1->component_type_
6472 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
6473 // /* HeapReference<Class> */ temp2 = value->klass_
6474 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
6475 // If heap poisoning is enabled, no need to unpoison `temp1`
6476 // nor `temp2`, as we are comparing two poisoned references.
6477 __ cmp(temp1, ShifterOperand(temp2));
Roland Levillain16d9f942016-08-25 17:27:56 +01006478
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006479 if (instruction->StaticTypeOfArrayIsObjectArray()) {
6480 Label do_put;
6481 __ b(&do_put, EQ);
6482 // If heap poisoning is enabled, the `temp1` reference has
6483 // not been unpoisoned yet; unpoison it now.
Roland Levillain3b359c72015-11-17 19:35:12 +00006484 __ MaybeUnpoisonHeapReference(temp1);
6485
Roland Levillain9d6e1f82016-09-05 15:57:33 +01006486 // /* HeapReference<Class> */ temp1 = temp1->super_class_
6487 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
6488 // If heap poisoning is enabled, no need to unpoison
6489 // `temp1`, as we are comparing against null below.
6490 __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
6491 __ Bind(&do_put);
6492 } else {
6493 __ b(slow_path->GetEntryLabel(), NE);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006494 }
6495 }
6496
Artem Serov6c916792016-07-11 14:02:34 +01006497 Register source = value;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006498 if (kPoisonHeapReferences) {
6499 // Note that in the case where `value` is a null reference,
6500 // we do not enter this block, as a null reference does not
6501 // need poisoning.
6502 DCHECK_EQ(value_type, Primitive::kPrimNot);
6503 __ Mov(temp1, value);
6504 __ PoisonHeapReference(temp1);
6505 source = temp1;
6506 }
6507
6508 if (index.IsConstant()) {
6509 size_t offset =
6510 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
6511 __ StoreToOffset(kStoreWord, source, array, offset);
6512 } else {
6513 DCHECK(index.IsRegister()) << index;
Artem Serov6c916792016-07-11 14:02:34 +01006514
6515 __ add(IP, array, ShifterOperand(data_offset));
6516 codegen_->StoreToShiftedRegOffset(value_type,
6517 Location::RegisterLocation(source),
6518 IP,
6519 index.AsRegister<Register>());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006520 }
6521
Roland Levillain3b359c72015-11-17 19:35:12 +00006522 if (!may_need_runtime_call_for_type_check) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006523 codegen_->MaybeRecordImplicitNullCheck(instruction);
6524 }
6525
6526 codegen_->MarkGCCard(temp1, temp2, array, value, instruction->GetValueCanBeNull());
6527
6528 if (done.IsLinked()) {
6529 __ Bind(&done);
6530 }
6531
6532 if (slow_path != nullptr) {
6533 __ Bind(slow_path->GetExitLabel());
6534 }
6535
6536 break;
6537 }
6538
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006539 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006540 Location value = locations->InAt(2);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006541 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00006542 size_t offset =
6543 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006544 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), array, offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006545 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006546 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01006547 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006548 }
6549 break;
6550 }
6551
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006552 case Primitive::kPrimFloat: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006553 Location value = locations->InAt(2);
6554 DCHECK(value.IsFpuRegister());
6555 if (index.IsConstant()) {
6556 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006557 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006558 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006559 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006560 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset);
6561 }
6562 break;
6563 }
6564
6565 case Primitive::kPrimDouble: {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006566 Location value = locations->InAt(2);
6567 DCHECK(value.IsFpuRegisterPair());
6568 if (index.IsConstant()) {
6569 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006570 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), array, offset);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006571 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01006572 __ add(IP, array, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8));
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006573 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset);
6574 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006575
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006576 break;
6577 }
6578
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006579 case Primitive::kPrimVoid:
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006580 LOG(FATAL) << "Unreachable type " << value_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07006581 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006582 }
Calin Juravle77520bc2015-01-12 18:45:46 +00006583
Roland Levillain80e67092016-01-08 16:04:55 +00006584 // Objects are handled in the switch.
6585 if (value_type != Primitive::kPrimNot) {
Calin Juravle77520bc2015-01-12 18:45:46 +00006586 codegen_->MaybeRecordImplicitNullCheck(instruction);
6587 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006588}
6589
6590void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01006591 LocationSummary* locations =
6592 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01006593 locations->SetInAt(0, Location::RequiresRegister());
6594 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006595}
6596
6597void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
6598 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01006599 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00006600 Register obj = locations->InAt(0).AsRegister<Register>();
6601 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006602 __ LoadFromOffset(kLoadWord, out, obj, offset);
Calin Juravle77520bc2015-01-12 18:45:46 +00006603 codegen_->MaybeRecordImplicitNullCheck(instruction);
jessicahandojo05765752016-09-09 19:01:32 -07006604 // Mask out compression flag from String's array length.
6605 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
Vladimir Markofdaf0f42016-10-13 19:29:53 +01006606 __ Lsr(out, out, 1u);
jessicahandojo05765752016-09-09 19:01:32 -07006607 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006608}
6609
Artem Serov328429f2016-07-06 16:23:04 +01006610void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
Artem Serov328429f2016-07-06 16:23:04 +01006611 LocationSummary* locations =
6612 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6613
6614 locations->SetInAt(0, Location::RequiresRegister());
6615 locations->SetInAt(1, Location::RegisterOrConstant(instruction->GetOffset()));
6616 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6617}
6618
6619void InstructionCodeGeneratorARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
6620 LocationSummary* locations = instruction->GetLocations();
6621 Location out = locations->Out();
6622 Location first = locations->InAt(0);
6623 Location second = locations->InAt(1);
6624
Artem Serov328429f2016-07-06 16:23:04 +01006625 if (second.IsRegister()) {
6626 __ add(out.AsRegister<Register>(),
6627 first.AsRegister<Register>(),
6628 ShifterOperand(second.AsRegister<Register>()));
6629 } else {
6630 __ AddConstant(out.AsRegister<Register>(),
6631 first.AsRegister<Register>(),
6632 second.GetConstant()->AsIntConstant()->GetValue());
6633 }
6634}
6635
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006636void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006637 RegisterSet caller_saves = RegisterSet::Empty();
6638 InvokeRuntimeCallingConvention calling_convention;
6639 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6640 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
6641 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Artem Serov2dd053d2017-03-08 14:54:06 +00006642
6643 HInstruction* index = instruction->InputAt(0);
6644 HInstruction* length = instruction->InputAt(1);
6645 // If both index and length are constants we can statically check the bounds. But if at least one
6646 // of them is not encodable ArmEncodableConstantOrRegister will create
6647 // Location::RequiresRegister() which is not desired to happen. Instead we create constant
6648 // locations.
6649 bool both_const = index->IsConstant() && length->IsConstant();
6650 locations->SetInAt(0, both_const
6651 ? Location::ConstantLocation(index->AsConstant())
6652 : ArmEncodableConstantOrRegister(index, CMP));
6653 locations->SetInAt(1, both_const
6654 ? Location::ConstantLocation(length->AsConstant())
6655 : ArmEncodableConstantOrRegister(length, CMP));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006656}
6657
6658void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
6659 LocationSummary* locations = instruction->GetLocations();
Artem Serov2dd053d2017-03-08 14:54:06 +00006660 Location index_loc = locations->InAt(0);
6661 Location length_loc = locations->InAt(1);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006662
Artem Serov2dd053d2017-03-08 14:54:06 +00006663 if (length_loc.IsConstant()) {
6664 int32_t length = helpers::Int32ConstantFrom(length_loc);
6665 if (index_loc.IsConstant()) {
6666 // BCE will remove the bounds check if we are guaranteed to pass.
6667 int32_t index = helpers::Int32ConstantFrom(index_loc);
6668 if (index < 0 || index >= length) {
6669 SlowPathCodeARM* slow_path =
6670 new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6671 codegen_->AddSlowPath(slow_path);
6672 __ b(slow_path->GetEntryLabel());
6673 } else {
6674 // Some optimization after BCE may have generated this, and we should not
6675 // generate a bounds check if it is a valid range.
6676 }
6677 return;
6678 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006679
Artem Serov2dd053d2017-03-08 14:54:06 +00006680 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6681 __ cmp(index_loc.AsRegister<Register>(), ShifterOperand(length));
6682 codegen_->AddSlowPath(slow_path);
6683 __ b(slow_path->GetEntryLabel(), HS);
6684 } else {
6685 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(instruction);
6686 if (index_loc.IsConstant()) {
6687 int32_t index = helpers::Int32ConstantFrom(index_loc);
6688 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index));
6689 } else {
6690 __ cmp(length_loc.AsRegister<Register>(), ShifterOperand(index_loc.AsRegister<Register>()));
6691 }
6692 codegen_->AddSlowPath(slow_path);
6693 __ b(slow_path->GetEntryLabel(), LS);
6694 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006695}
6696
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006697void CodeGeneratorARM::MarkGCCard(Register temp,
6698 Register card,
6699 Register object,
6700 Register value,
6701 bool can_be_null) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +00006702 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006703 if (can_be_null) {
6704 __ CompareAndBranchIfZero(value, &is_null);
6705 }
Andreas Gampe542451c2016-07-26 09:02:02 -07006706 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006707 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
6708 __ strb(card, Address(card, temp));
Nicolas Geoffray07276db2015-05-18 14:22:09 +01006709 if (can_be_null) {
6710 __ Bind(&is_null);
6711 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01006712}
6713
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01006714void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006715 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006716}
6717
6718void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006719 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6720}
6721
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006722void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01006723 LocationSummary* locations =
6724 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01006725 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006726}
6727
6728void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006729 HBasicBlock* block = instruction->GetBlock();
6730 if (block->GetLoopInformation() != nullptr) {
6731 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6732 // The back edge will generate the suspend check.
6733 return;
6734 }
6735 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6736 // The goto will generate the suspend check.
6737 return;
6738 }
6739 GenerateSuspendCheck(instruction, nullptr);
6740}
6741
6742void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction,
6743 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006744 SuspendCheckSlowPathARM* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01006745 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath());
6746 if (slow_path == nullptr) {
6747 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor);
6748 instruction->SetSlowPath(slow_path);
6749 codegen_->AddSlowPath(slow_path);
6750 if (successor != nullptr) {
6751 DCHECK(successor->IsLoopHeader());
6752 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
6753 }
6754 } else {
6755 DCHECK_EQ(slow_path->GetSuccessor(), successor);
6756 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006757
Nicolas Geoffray44b819e2014-11-06 12:00:54 +00006758 __ LoadFromOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07006759 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006760 if (successor == nullptr) {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006761 __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006762 __ Bind(slow_path->GetReturnLabel());
6763 } else {
Nicolas Geoffray2bcb4312015-07-01 12:22:56 +01006764 __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01006765 __ b(slow_path->GetEntryLabel());
6766 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00006767}
6768
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006769ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
6770 return codegen_->GetAssembler();
6771}
6772
6773void ParallelMoveResolverARM::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006774 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006775 Location source = move->GetSource();
6776 Location destination = move->GetDestination();
6777
6778 if (source.IsRegister()) {
6779 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006780 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006781 } else if (destination.IsFpuRegister()) {
6782 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006783 } else {
6784 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00006785 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006786 SP, destination.GetStackIndex());
6787 }
6788 } else if (source.IsStackSlot()) {
6789 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006790 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(),
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006791 SP, source.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006792 } else if (destination.IsFpuRegister()) {
6793 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006794 } else {
6795 DCHECK(destination.IsStackSlot());
6796 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex());
6797 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6798 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006799 } else if (source.IsFpuRegister()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006800 if (destination.IsRegister()) {
6801 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
6802 } else if (destination.IsFpuRegister()) {
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006803 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006804 } else {
6805 DCHECK(destination.IsStackSlot());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006806 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex());
6807 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006808 } else if (source.IsDoubleStackSlot()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006809 if (destination.IsDoubleStackSlot()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006810 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex());
6811 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006812 } else if (destination.IsRegisterPair()) {
6813 DCHECK(ExpectedPairLayout(destination));
6814 __ LoadFromOffset(
6815 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex());
6816 } else {
6817 DCHECK(destination.IsFpuRegisterPair()) << destination;
6818 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6819 SP,
6820 source.GetStackIndex());
6821 }
6822 } else if (source.IsRegisterPair()) {
6823 if (destination.IsRegisterPair()) {
6824 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
6825 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
David Brazdil74eb1b22015-12-14 11:44:01 +00006826 } else if (destination.IsFpuRegisterPair()) {
6827 __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6828 source.AsRegisterPairLow<Register>(),
6829 source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006830 } else {
6831 DCHECK(destination.IsDoubleStackSlot()) << destination;
6832 DCHECK(ExpectedPairLayout(source));
6833 __ StoreToOffset(
6834 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
6835 }
6836 } else if (source.IsFpuRegisterPair()) {
David Brazdil74eb1b22015-12-14 11:44:01 +00006837 if (destination.IsRegisterPair()) {
6838 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6839 destination.AsRegisterPairHigh<Register>(),
6840 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6841 } else if (destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006842 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
6843 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
6844 } else {
6845 DCHECK(destination.IsDoubleStackSlot()) << destination;
6846 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()),
6847 SP,
6848 destination.GetStackIndex());
6849 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006850 } else {
6851 DCHECK(source.IsConstant()) << source;
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00006852 HConstant* constant = source.GetConstant();
6853 if (constant->IsIntConstant() || constant->IsNullConstant()) {
6854 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006855 if (destination.IsRegister()) {
6856 __ LoadImmediate(destination.AsRegister<Register>(), value);
6857 } else {
6858 DCHECK(destination.IsStackSlot());
6859 __ LoadImmediate(IP, value);
6860 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6861 }
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006862 } else if (constant->IsLongConstant()) {
6863 int64_t value = constant->AsLongConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006864 if (destination.IsRegisterPair()) {
6865 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value));
6866 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value));
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006867 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006868 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006869 __ LoadImmediate(IP, Low32Bits(value));
6870 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6871 __ LoadImmediate(IP, High32Bits(value));
6872 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6873 }
6874 } else if (constant->IsDoubleConstant()) {
6875 double value = constant->AsDoubleConstant()->GetValue();
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006876 if (destination.IsFpuRegisterPair()) {
6877 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006878 } else {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006879 DCHECK(destination.IsDoubleStackSlot()) << destination;
6880 uint64_t int_value = bit_cast<uint64_t, double>(value);
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006881 __ LoadImmediate(IP, Low32Bits(int_value));
6882 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6883 __ LoadImmediate(IP, High32Bits(int_value));
6884 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize));
6885 }
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006886 } else {
Nicolas Geoffray6c2dff82015-01-21 14:56:54 +00006887 DCHECK(constant->IsFloatConstant()) << constant->DebugName();
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006888 float value = constant->AsFloatConstant()->GetValue();
6889 if (destination.IsFpuRegister()) {
6890 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value);
6891 } else {
6892 DCHECK(destination.IsStackSlot());
6893 __ LoadImmediate(IP, bit_cast<int32_t, float>(value));
6894 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
6895 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01006896 }
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006897 }
6898}
6899
6900void ParallelMoveResolverARM::Exchange(Register reg, int mem) {
6901 __ Mov(IP, reg);
6902 __ LoadFromOffset(kLoadWord, reg, SP, mem);
6903 __ StoreToOffset(kStoreWord, IP, SP, mem);
6904}
6905
6906void ParallelMoveResolverARM::Exchange(int mem1, int mem2) {
6907 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters());
6908 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0;
6909 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()),
6910 SP, mem1 + stack_offset);
6911 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset);
6912 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()),
6913 SP, mem2 + stack_offset);
6914 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset);
6915}
6916
6917void ParallelMoveResolverARM::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01006918 MoveOperands* move = moves_[index];
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006919 Location source = move->GetSource();
6920 Location destination = move->GetDestination();
6921
6922 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006923 DCHECK_NE(source.AsRegister<Register>(), IP);
6924 DCHECK_NE(destination.AsRegister<Register>(), IP);
6925 __ Mov(IP, source.AsRegister<Register>());
6926 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>());
6927 __ Mov(destination.AsRegister<Register>(), IP);
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006928 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006929 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006930 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00006931 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006932 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
6933 Exchange(source.GetStackIndex(), destination.GetStackIndex());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006934 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006935 __ vmovrs(IP, source.AsFpuRegister<SRegister>());
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006936 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>());
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006937 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006938 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) {
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006939 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006940 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>());
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006941 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006942 __ vmovrrd(destination.AsRegisterPairLow<Register>(),
6943 destination.AsRegisterPairHigh<Register>(),
6944 DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006945 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006946 Register low_reg = source.IsRegisterPair()
6947 ? source.AsRegisterPairLow<Register>()
6948 : destination.AsRegisterPairLow<Register>();
6949 int mem = source.IsRegisterPair()
6950 ? destination.GetStackIndex()
6951 : source.GetStackIndex();
6952 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination));
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006953 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1));
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006954 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006955 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006956 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) {
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006957 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>());
6958 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006959 __ vmovd(DTMP, first);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006960 __ vmovd(first, second);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006961 __ vmovd(second, DTMP);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006962 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) {
6963 DRegister reg = source.IsFpuRegisterPair()
6964 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())
6965 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>());
6966 int mem = source.IsFpuRegisterPair()
6967 ? destination.GetStackIndex()
6968 : source.GetStackIndex();
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006969 __ vmovd(DTMP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006970 __ LoadDFromOffset(reg, SP, mem);
Nicolas Geoffrayffe8a572015-02-11 01:10:39 +00006971 __ StoreDToOffset(DTMP, SP, mem);
Nicolas Geoffray840e5462015-01-07 16:01:24 +00006972 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) {
6973 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>()
6974 : destination.AsFpuRegister<SRegister>();
6975 int mem = source.IsFpuRegister()
6976 ? destination.GetStackIndex()
6977 : source.GetStackIndex();
6978
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006979 __ vmovrs(IP, reg);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +00006980 __ LoadSFromOffset(reg, SP, mem);
Nicolas Geoffraya8eef822015-01-16 11:14:27 +00006981 __ StoreToOffset(kStoreWord, IP, SP, mem);
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006982 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006983 Exchange(source.GetStackIndex(), destination.GetStackIndex());
6984 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize));
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006985 } else {
Nicolas Geoffray53f12622015-01-13 18:04:41 +00006986 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination;
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01006987 }
6988}
6989
6990void ParallelMoveResolverARM::SpillScratch(int reg) {
6991 __ Push(static_cast<Register>(reg));
6992}
6993
6994void ParallelMoveResolverARM::RestoreScratch(int reg) {
6995 __ Pop(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01006996}
6997
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01006998HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
6999 HLoadClass::LoadKind desired_class_load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007000 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007001 case HLoadClass::LoadKind::kInvalid:
7002 LOG(FATAL) << "UNREACHABLE";
7003 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007004 case HLoadClass::LoadKind::kReferrersClass:
7005 break;
7006 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
7007 DCHECK(!GetCompilerOptions().GetCompilePic());
7008 break;
7009 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
7010 DCHECK(GetCompilerOptions().GetCompilePic());
7011 break;
7012 case HLoadClass::LoadKind::kBootImageAddress:
7013 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007014 case HLoadClass::LoadKind::kBssEntry:
7015 DCHECK(!Runtime::Current()->UseJitCompilation());
7016 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007017 case HLoadClass::LoadKind::kJitTableAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007018 DCHECK(Runtime::Current()->UseJitCompilation());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007019 break;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007020 case HLoadClass::LoadKind::kDexCacheViaMethod:
7021 break;
7022 }
7023 return desired_class_load_kind;
7024}
7025
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007026void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00007027 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
7028 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007029 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00007030 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007031 cls,
7032 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00007033 Location::RegisterLocation(R0));
Vladimir Markoea4c1262017-02-06 19:59:33 +00007034 DCHECK_EQ(calling_convention.GetRegisterAt(0), R0);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007035 return;
7036 }
Vladimir Marko41559982017-01-06 14:04:23 +00007037 DCHECK(!cls->NeedsAccessCheck());
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007038
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007039 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
7040 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007041 ? LocationSummary::kCallOnSlowPath
7042 : LocationSummary::kNoCall;
7043 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007044 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007045 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007046 }
7047
Vladimir Marko41559982017-01-06 14:04:23 +00007048 if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007049 locations->SetInAt(0, Location::RequiresRegister());
7050 }
7051 locations->SetOut(Location::RequiresRegister());
Vladimir Markoea4c1262017-02-06 19:59:33 +00007052 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
7053 if (!kUseReadBarrier || kUseBakerReadBarrier) {
7054 // Rely on the type resolution or initialization and marking to save everything we need.
7055 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
7056 // to the custom calling convention) or by marking, so we request a different temp.
7057 locations->AddTemp(Location::RequiresRegister());
7058 RegisterSet caller_saves = RegisterSet::Empty();
7059 InvokeRuntimeCallingConvention calling_convention;
7060 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7061 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
7062 // that the the kPrimNot result register is the same as the first argument register.
7063 locations->SetCustomSlowPathCallerSaves(caller_saves);
7064 } else {
7065 // For non-Baker read barrier we have a temp-clobbering call.
7066 }
7067 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007068}
7069
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007070// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7071// move.
7072void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00007073 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
7074 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
7075 codegen_->GenerateLoadClassRuntimeCall(cls);
Calin Juravle580b6092015-10-06 17:35:58 +01007076 return;
7077 }
Vladimir Marko41559982017-01-06 14:04:23 +00007078 DCHECK(!cls->NeedsAccessCheck());
Calin Juravle580b6092015-10-06 17:35:58 +01007079
Vladimir Marko41559982017-01-06 14:04:23 +00007080 LocationSummary* locations = cls->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007081 Location out_loc = locations->Out();
7082 Register out = out_loc.AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007083
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007084 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
7085 ? kWithoutReadBarrier
7086 : kCompilerReadBarrierOption;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007087 bool generate_null_check = false;
Vladimir Marko41559982017-01-06 14:04:23 +00007088 switch (load_kind) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007089 case HLoadClass::LoadKind::kReferrersClass: {
7090 DCHECK(!cls->CanCallRuntime());
7091 DCHECK(!cls->MustGenerateClinitCheck());
7092 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
7093 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartier31b12e32016-09-02 17:11:57 -07007094 GenerateGcRootFieldLoad(cls,
7095 out_loc,
7096 current_method,
7097 ArtMethod::DeclaringClassOffset().Int32Value(),
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007098 read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007099 break;
7100 }
7101 case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007102 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007103 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007104 __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
7105 cls->GetTypeIndex()));
7106 break;
7107 }
7108 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007109 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007110 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007111 CodeGeneratorARM::PcRelativePatchInfo* labels =
7112 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
7113 __ BindTrackedLabel(&labels->movw_label);
7114 __ movw(out, /* placeholder */ 0u);
7115 __ BindTrackedLabel(&labels->movt_label);
7116 __ movt(out, /* placeholder */ 0u);
7117 __ BindTrackedLabel(&labels->add_pc_label);
7118 __ add(out, out, ShifterOperand(PC));
7119 break;
7120 }
7121 case HLoadClass::LoadKind::kBootImageAddress: {
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007122 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007123 uint32_t address = dchecked_integral_cast<uint32_t>(
7124 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
7125 DCHECK_NE(address, 0u);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007126 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
7127 break;
7128 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007129 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Markoea4c1262017-02-06 19:59:33 +00007130 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
7131 ? locations->GetTemp(0).AsRegister<Register>()
7132 : out;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007133 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko1998cd02017-01-13 13:02:58 +00007134 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007135 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00007136 __ movw(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007137 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00007138 __ movt(temp, /* placeholder */ 0u);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007139 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Markoea4c1262017-02-06 19:59:33 +00007140 __ add(temp, temp, ShifterOperand(PC));
7141 GenerateGcRootFieldLoad(cls, out_loc, temp, /* offset */ 0, read_barrier_option);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007142 generate_null_check = true;
7143 break;
7144 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007145 case HLoadClass::LoadKind::kJitTableAddress: {
7146 __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
7147 cls->GetTypeIndex(),
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007148 cls->GetClass()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007149 // /* GcRoot<mirror::Class> */ out = *out
Vladimir Markoea4c1262017-02-06 19:59:33 +00007150 GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, read_barrier_option);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007151 break;
7152 }
Vladimir Marko41559982017-01-06 14:04:23 +00007153 case HLoadClass::LoadKind::kDexCacheViaMethod:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007154 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00007155 LOG(FATAL) << "UNREACHABLE";
7156 UNREACHABLE();
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007157 }
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007158
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007159 if (generate_null_check || cls->MustGenerateClinitCheck()) {
7160 DCHECK(cls->CanCallRuntime());
Artem Serovf4d6aee2016-07-11 10:41:45 +01007161 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007162 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
7163 codegen_->AddSlowPath(slow_path);
7164 if (generate_null_check) {
7165 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
7166 }
7167 if (cls->MustGenerateClinitCheck()) {
7168 GenerateClassInitializationCheck(slow_path, out);
7169 } else {
7170 __ Bind(slow_path->GetExitLabel());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007171 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007172 }
7173}
7174
7175void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) {
7176 LocationSummary* locations =
7177 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
7178 locations->SetInAt(0, Location::RequiresRegister());
7179 if (check->HasUses()) {
7180 locations->SetOut(Location::SameAsFirstInput());
7181 }
7182}
7183
7184void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007185 // We assume the class is not null.
Artem Serovf4d6aee2016-07-11 10:41:45 +01007186 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007187 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007188 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00007189 GenerateClassInitializationCheck(slow_path,
7190 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007191}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007192
Nicolas Geoffray424f6762014-11-03 14:51:25 +00007193void InstructionCodeGeneratorARM::GenerateClassInitializationCheck(
Artem Serovf4d6aee2016-07-11 10:41:45 +01007194 SlowPathCodeARM* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01007195 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value());
7196 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized));
7197 __ b(slow_path->GetEntryLabel(), LT);
7198 // Even if the initialized flag is set, we may be in a situation where caches are not synced
7199 // properly. Therefore, we do a memory fence.
7200 __ dmb(ISH);
7201 __ Bind(slow_path->GetExitLabel());
7202}
7203
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007204HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
7205 HLoadString::LoadKind desired_string_load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007206 switch (desired_string_load_kind) {
7207 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
7208 DCHECK(!GetCompilerOptions().GetCompilePic());
7209 break;
7210 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
7211 DCHECK(GetCompilerOptions().GetCompilePic());
7212 break;
7213 case HLoadString::LoadKind::kBootImageAddress:
7214 break;
Vladimir Markoaad75c62016-10-03 08:46:48 +00007215 case HLoadString::LoadKind::kBssEntry:
Calin Juravleffc87072016-04-20 14:22:09 +01007216 DCHECK(!Runtime::Current()->UseJitCompilation());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007217 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007218 case HLoadString::LoadKind::kJitTableAddress:
7219 DCHECK(Runtime::Current()->UseJitCompilation());
7220 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007221 case HLoadString::LoadKind::kDexCacheViaMethod:
7222 break;
7223 }
7224 return desired_string_load_kind;
7225}
7226
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007227void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007228 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00007229 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007230 HLoadString::LoadKind load_kind = load->GetLoadKind();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007231 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007232 locations->SetOut(Location::RegisterLocation(R0));
7233 } else {
7234 locations->SetOut(Location::RequiresRegister());
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007235 if (load_kind == HLoadString::LoadKind::kBssEntry) {
7236 if (!kUseReadBarrier || kUseBakerReadBarrier) {
Vladimir Markoea4c1262017-02-06 19:59:33 +00007237 // Rely on the pResolveString and marking to save everything we need, including temps.
7238 // Note that IP may be clobbered by saving/restoring the live register (only one thanks
7239 // to the custom calling convention) or by marking, so we request a different temp.
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007240 locations->AddTemp(Location::RequiresRegister());
7241 RegisterSet caller_saves = RegisterSet::Empty();
7242 InvokeRuntimeCallingConvention calling_convention;
7243 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7244 // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK()
7245 // that the the kPrimNot result register is the same as the first argument register.
7246 locations->SetCustomSlowPathCallerSaves(caller_saves);
7247 } else {
7248 // For non-Baker read barrier we have a temp-clobbering call.
7249 }
7250 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007251 }
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007252}
7253
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007254// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7255// move.
7256void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01007257 LocationSummary* locations = load->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007258 Location out_loc = locations->Out();
7259 Register out = out_loc.AsRegister<Register>();
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007260 HLoadString::LoadKind load_kind = load->GetLoadKind();
Roland Levillain3b359c72015-11-17 19:35:12 +00007261
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007262 switch (load_kind) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007263 case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007264 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007265 __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
7266 load->GetStringIndex()));
7267 return; // No dex cache slow path.
7268 }
7269 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00007270 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007271 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007272 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007273 __ BindTrackedLabel(&labels->movw_label);
7274 __ movw(out, /* placeholder */ 0u);
7275 __ BindTrackedLabel(&labels->movt_label);
7276 __ movt(out, /* placeholder */ 0u);
7277 __ BindTrackedLabel(&labels->add_pc_label);
7278 __ add(out, out, ShifterOperand(PC));
7279 return; // No dex cache slow path.
7280 }
7281 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007282 uint32_t address = dchecked_integral_cast<uint32_t>(
7283 reinterpret_cast<uintptr_t>(load->GetString().Get()));
7284 DCHECK_NE(address, 0u);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007285 __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
7286 return; // No dex cache slow path.
7287 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00007288 case HLoadString::LoadKind::kBssEntry: {
7289 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markoea4c1262017-02-06 19:59:33 +00007290 Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
7291 ? locations->GetTemp(0).AsRegister<Register>()
7292 : out;
Vladimir Markoaad75c62016-10-03 08:46:48 +00007293 CodeGeneratorARM::PcRelativePatchInfo* labels =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007294 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Vladimir Markoaad75c62016-10-03 08:46:48 +00007295 __ BindTrackedLabel(&labels->movw_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007296 __ movw(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007297 __ BindTrackedLabel(&labels->movt_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007298 __ movt(temp, /* placeholder */ 0u);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007299 __ BindTrackedLabel(&labels->add_pc_label);
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007300 __ add(temp, temp, ShifterOperand(PC));
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007301 GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007302 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
7303 codegen_->AddSlowPath(slow_path);
7304 __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
7305 __ Bind(slow_path->GetExitLabel());
7306 return;
7307 }
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007308 case HLoadString::LoadKind::kJitTableAddress: {
7309 __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00007310 load->GetStringIndex(),
7311 load->GetString()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007312 // /* GcRoot<mirror::String> */ out = *out
7313 GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
7314 return;
7315 }
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007316 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07007317 break;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007318 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007319
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007320 // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
7321 DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
7322 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko94ce9c22016-09-30 14:50:51 +01007323 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08007324 __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Christina Wadsworthd8ec6db2016-08-30 17:19:14 -07007325 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
7326 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00007327}
7328
David Brazdilcb1c0552015-08-04 16:22:25 +01007329static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07007330 return Thread::ExceptionOffset<kArmPointerSize>().Int32Value();
David Brazdilcb1c0552015-08-04 16:22:25 +01007331}
7332
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007333void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
7334 LocationSummary* locations =
7335 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
7336 locations->SetOut(Location::RequiresRegister());
7337}
7338
7339void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00007340 Register out = load->GetLocations()->Out().AsRegister<Register>();
David Brazdilcb1c0552015-08-04 16:22:25 +01007341 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
7342}
7343
7344void LocationsBuilderARM::VisitClearException(HClearException* clear) {
7345 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
7346}
7347
7348void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007349 __ LoadImmediate(IP, 0);
David Brazdilcb1c0552015-08-04 16:22:25 +01007350 __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007351}
7352
7353void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
7354 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01007355 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007356 InvokeRuntimeCallingConvention calling_convention;
7357 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7358}
7359
7360void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01007361 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007362 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00007363}
7364
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007365// Temp is used for read barrier.
7366static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
7367 if (kEmitCompilerReadBarrier &&
7368 (kUseBakerReadBarrier ||
7369 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7370 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7371 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
7372 return 1;
7373 }
7374 return 0;
7375}
7376
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007377// Interface case has 3 temps, one for holding the number of interfaces, one for the current
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007378// interface pointer, one for loading the current interface.
7379// The other checks have one temp for loading the object's class.
7380static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
7381 if (type_check_kind == TypeCheckKind::kInterfaceCheck) {
7382 return 3;
7383 }
7384 return 1 + NumberOfInstanceOfTemps(type_check_kind);
Roland Levillainc9285912015-12-18 10:38:42 +00007385}
7386
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007387void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007388 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Roland Levillain3b359c72015-11-17 19:35:12 +00007389 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Vladimir Marko70e97462016-08-09 11:04:26 +01007390 bool baker_read_barrier_slow_path = false;
Roland Levillain3b359c72015-11-17 19:35:12 +00007391 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007392 case TypeCheckKind::kExactCheck:
7393 case TypeCheckKind::kAbstractClassCheck:
7394 case TypeCheckKind::kClassHierarchyCheck:
7395 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007396 call_kind =
7397 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
Vladimir Marko70e97462016-08-09 11:04:26 +01007398 baker_read_barrier_slow_path = kUseBakerReadBarrier;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007399 break;
7400 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007401 case TypeCheckKind::kUnresolvedCheck:
7402 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007403 call_kind = LocationSummary::kCallOnSlowPath;
7404 break;
7405 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007406
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007407 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Vladimir Marko70e97462016-08-09 11:04:26 +01007408 if (baker_read_barrier_slow_path) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01007409 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Vladimir Marko70e97462016-08-09 11:04:26 +01007410 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007411 locations->SetInAt(0, Location::RequiresRegister());
7412 locations->SetInAt(1, Location::RequiresRegister());
7413 // The "out" register is used as a temporary, so it overlaps with the inputs.
7414 // Note that TypeCheckSlowPathARM uses this register too.
7415 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007416 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007417}
7418
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007419void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007420 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007421 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007422 Location obj_loc = locations->InAt(0);
7423 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007424 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007425 Location out_loc = locations->Out();
7426 Register out = out_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007427 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7428 DCHECK_LE(num_temps, 1u);
7429 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007430 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007431 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7432 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7433 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007434 Label done;
7435 Label* const final_label = codegen_->GetFinalLabel(instruction, &done);
Artem Serovf4d6aee2016-07-11 10:41:45 +01007436 SlowPathCodeARM* slow_path = nullptr;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007437
7438 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007439 // avoid null check if we know obj is not null.
7440 if (instruction->MustDoNullCheck()) {
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007441 DCHECK_NE(out, obj);
7442 __ LoadImmediate(out, 0);
7443 __ CompareAndBranchIfZero(obj, final_label);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007444 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007445
Roland Levillainc9285912015-12-18 10:38:42 +00007446 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007447 case TypeCheckKind::kExactCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007448 // /* HeapReference<Class> */ out = obj->klass_
7449 GenerateReferenceLoadTwoRegisters(instruction,
7450 out_loc,
7451 obj_loc,
7452 class_offset,
7453 maybe_temp_loc,
7454 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007455 // Classes must be equal for the instanceof to succeed.
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007456 __ cmp(out, ShifterOperand(cls));
7457 // We speculatively set the result to false without changing the condition
7458 // flags, which allows us to avoid some branching later.
7459 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7460
7461 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7462 // we check that the output is in a low register, so that a 16-bit MOV
7463 // encoding can be used.
7464 if (ArmAssembler::IsLowRegister(out)) {
7465 __ it(EQ);
7466 __ mov(out, ShifterOperand(1), EQ);
7467 } else {
7468 __ b(final_label, NE);
7469 __ LoadImmediate(out, 1);
7470 }
7471
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007472 break;
7473 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007474
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007475 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007476 // /* HeapReference<Class> */ out = obj->klass_
7477 GenerateReferenceLoadTwoRegisters(instruction,
7478 out_loc,
7479 obj_loc,
7480 class_offset,
7481 maybe_temp_loc,
7482 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007483 // If the class is abstract, we eagerly fetch the super class of the
7484 // object to avoid doing a comparison we know will fail.
7485 Label loop;
7486 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007487 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007488 GenerateReferenceLoadOneRegister(instruction,
7489 out_loc,
7490 super_offset,
7491 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007492 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007493 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007494 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007495 __ cmp(out, ShifterOperand(cls));
7496 __ b(&loop, NE);
7497 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007498 break;
7499 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007500
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007501 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007502 // /* HeapReference<Class> */ out = obj->klass_
7503 GenerateReferenceLoadTwoRegisters(instruction,
7504 out_loc,
7505 obj_loc,
7506 class_offset,
7507 maybe_temp_loc,
7508 kCompilerReadBarrierOption);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007509 // Walk over the class hierarchy to find a match.
7510 Label loop, success;
7511 __ Bind(&loop);
7512 __ cmp(out, ShifterOperand(cls));
7513 __ b(&success, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007514 // /* HeapReference<Class> */ out = out->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007515 GenerateReferenceLoadOneRegister(instruction,
7516 out_loc,
7517 super_offset,
7518 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007519 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007520 // This is essentially a null check, but it sets the condition flags to the
7521 // proper value for the code that follows the loop, i.e. not `EQ`.
7522 __ cmp(out, ShifterOperand(1));
7523 __ b(&loop, HS);
7524
7525 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7526 // we check that the output is in a low register, so that a 16-bit MOV
7527 // encoding can be used.
7528 if (ArmAssembler::IsLowRegister(out)) {
7529 // If `out` is null, we use it for the result, and the condition flags
7530 // have already been set to `NE`, so the IT block that comes afterwards
7531 // (and which handles the successful case) turns into a NOP (instead of
7532 // overwriting `out`).
7533 __ Bind(&success);
7534 // There is only one branch to the `success` label (which is bound to this
7535 // IT block), and it has the same condition, `EQ`, so in that case the MOV
7536 // is executed.
7537 __ it(EQ);
7538 __ mov(out, ShifterOperand(1), EQ);
7539 } else {
7540 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007541 __ b(final_label);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007542 __ Bind(&success);
7543 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007544 }
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007545
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007546 break;
7547 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007548
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007549 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007550 // /* HeapReference<Class> */ out = obj->klass_
7551 GenerateReferenceLoadTwoRegisters(instruction,
7552 out_loc,
7553 obj_loc,
7554 class_offset,
7555 maybe_temp_loc,
7556 kCompilerReadBarrierOption);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007557 // Do an exact check.
7558 Label exact_check;
7559 __ cmp(out, ShifterOperand(cls));
7560 __ b(&exact_check, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007561 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007562 // /* HeapReference<Class> */ out = out->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007563 GenerateReferenceLoadOneRegister(instruction,
7564 out_loc,
7565 component_offset,
7566 maybe_temp_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007567 kCompilerReadBarrierOption);
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007568 // If `out` is null, we use it for the result, and jump to the final label.
Anton Kirilov6f644202017-02-27 18:29:45 +00007569 __ CompareAndBranchIfZero(out, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007570 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
7571 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
Anton Kirilov1e7bb5a2017-03-17 12:30:44 +00007572 __ cmp(out, ShifterOperand(0));
7573 // We speculatively set the result to false without changing the condition
7574 // flags, which allows us to avoid some branching later.
7575 __ mov(out, ShifterOperand(0), AL, kCcKeep);
7576
7577 // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8,
7578 // we check that the output is in a low register, so that a 16-bit MOV
7579 // encoding can be used.
7580 if (ArmAssembler::IsLowRegister(out)) {
7581 __ Bind(&exact_check);
7582 __ it(EQ);
7583 __ mov(out, ShifterOperand(1), EQ);
7584 } else {
7585 __ b(final_label, NE);
7586 __ Bind(&exact_check);
7587 __ LoadImmediate(out, 1);
7588 }
7589
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007590 break;
7591 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007592
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007593 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier9fd8c602016-11-14 14:38:53 -08007594 // No read barrier since the slow path will retry upon failure.
7595 // /* HeapReference<Class> */ out = obj->klass_
7596 GenerateReferenceLoadTwoRegisters(instruction,
7597 out_loc,
7598 obj_loc,
7599 class_offset,
7600 maybe_temp_loc,
7601 kWithoutReadBarrier);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007602 __ cmp(out, ShifterOperand(cls));
7603 DCHECK(locations->OnlyCallsOnSlowPath());
Roland Levillain3b359c72015-11-17 19:35:12 +00007604 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7605 /* is_fatal */ false);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007606 codegen_->AddSlowPath(slow_path);
7607 __ b(slow_path->GetEntryLabel(), NE);
7608 __ LoadImmediate(out, 1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007609 break;
7610 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007611
Calin Juravle98893e12015-10-02 21:05:03 +01007612 case TypeCheckKind::kUnresolvedCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007613 case TypeCheckKind::kInterfaceCheck: {
7614 // Note that we indeed only call on slow path, but we always go
Roland Levillaine3f43ac2016-01-19 15:07:47 +00007615 // into the slow path for the unresolved and interface check
Roland Levillain3b359c72015-11-17 19:35:12 +00007616 // cases.
7617 //
7618 // We cannot directly call the InstanceofNonTrivial runtime
7619 // entry point without resorting to a type checking slow path
7620 // here (i.e. by calling InvokeRuntime directly), as it would
7621 // require to assign fixed registers for the inputs of this
7622 // HInstanceOf instruction (following the runtime calling
7623 // convention), which might be cluttered by the potential first
7624 // read barrier emission at the beginning of this method.
Roland Levillainc9285912015-12-18 10:38:42 +00007625 //
7626 // TODO: Introduce a new runtime entry point taking the object
7627 // to test (instead of its class) as argument, and let it deal
7628 // with the read barrier issues. This will let us refactor this
7629 // case of the `switch` code as it was previously (with a direct
7630 // call to the runtime not using a type checking slow path).
7631 // This should also be beneficial for the other cases above.
Roland Levillain3b359c72015-11-17 19:35:12 +00007632 DCHECK(locations->OnlyCallsOnSlowPath());
7633 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7634 /* is_fatal */ false);
7635 codegen_->AddSlowPath(slow_path);
7636 __ b(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007637 break;
7638 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007639 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01007640
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007641 if (done.IsLinked()) {
7642 __ Bind(&done);
7643 }
7644
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007645 if (slow_path != nullptr) {
7646 __ Bind(slow_path->GetExitLabel());
7647 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00007648}
7649
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007650void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007651 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7652 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
7653
Roland Levillain3b359c72015-11-17 19:35:12 +00007654 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
7655 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007656 case TypeCheckKind::kExactCheck:
7657 case TypeCheckKind::kAbstractClassCheck:
7658 case TypeCheckKind::kClassHierarchyCheck:
7659 case TypeCheckKind::kArrayObjectCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007660 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
7661 LocationSummary::kCallOnSlowPath :
7662 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007663 break;
7664 case TypeCheckKind::kArrayCheck:
Roland Levillain3b359c72015-11-17 19:35:12 +00007665 case TypeCheckKind::kUnresolvedCheck:
7666 case TypeCheckKind::kInterfaceCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007667 call_kind = LocationSummary::kCallOnSlowPath;
7668 break;
7669 }
7670
Roland Levillain3b359c72015-11-17 19:35:12 +00007671 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
7672 locations->SetInAt(0, Location::RequiresRegister());
7673 locations->SetInAt(1, Location::RequiresRegister());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007674 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007675}
7676
7677void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) {
Roland Levillainc9285912015-12-18 10:38:42 +00007678 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007679 LocationSummary* locations = instruction->GetLocations();
Roland Levillain3b359c72015-11-17 19:35:12 +00007680 Location obj_loc = locations->InAt(0);
7681 Register obj = obj_loc.AsRegister<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00007682 Register cls = locations->InAt(1).AsRegister<Register>();
Roland Levillain3b359c72015-11-17 19:35:12 +00007683 Location temp_loc = locations->GetTemp(0);
7684 Register temp = temp_loc.AsRegister<Register>();
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007685 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
7686 DCHECK_LE(num_temps, 3u);
7687 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
7688 Location maybe_temp3_loc = (num_temps >= 3) ? locations->GetTemp(2) : Location::NoLocation();
7689 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7690 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7691 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7692 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
7693 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
7694 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
7695 const uint32_t object_array_data_offset =
7696 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007697
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007698 // Always false for read barriers since we may need to go to the entrypoint for non-fatal cases
7699 // from false negatives. The false negatives may come from avoiding read barriers below. Avoiding
7700 // read barriers is done for performance and code size reasons.
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007701 bool is_type_check_slow_path_fatal = false;
7702 if (!kEmitCompilerReadBarrier) {
7703 is_type_check_slow_path_fatal =
7704 (type_check_kind == TypeCheckKind::kExactCheck ||
7705 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
7706 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
7707 type_check_kind == TypeCheckKind::kArrayObjectCheck) &&
7708 !instruction->CanThrowIntoCatchBlock();
7709 }
Artem Serovf4d6aee2016-07-11 10:41:45 +01007710 SlowPathCodeARM* type_check_slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00007711 new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction,
7712 is_type_check_slow_path_fatal);
7713 codegen_->AddSlowPath(type_check_slow_path);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007714
7715 Label done;
Anton Kirilov6f644202017-02-27 18:29:45 +00007716 Label* final_label = codegen_->GetFinalLabel(instruction, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007717 // Avoid null check if we know obj is not null.
7718 if (instruction->MustDoNullCheck()) {
Anton Kirilov6f644202017-02-27 18:29:45 +00007719 __ CompareAndBranchIfZero(obj, final_label);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007720 }
7721
Roland Levillain3b359c72015-11-17 19:35:12 +00007722 switch (type_check_kind) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007723 case TypeCheckKind::kExactCheck:
7724 case TypeCheckKind::kArrayCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007725 // /* HeapReference<Class> */ temp = obj->klass_
7726 GenerateReferenceLoadTwoRegisters(instruction,
7727 temp_loc,
7728 obj_loc,
7729 class_offset,
7730 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007731 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007732
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007733 __ cmp(temp, ShifterOperand(cls));
7734 // Jump to slow path for throwing the exception or doing a
7735 // more involved array check.
Roland Levillain3b359c72015-11-17 19:35:12 +00007736 __ b(type_check_slow_path->GetEntryLabel(), NE);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007737 break;
7738 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007739
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007740 case TypeCheckKind::kAbstractClassCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007741 // /* HeapReference<Class> */ temp = obj->klass_
7742 GenerateReferenceLoadTwoRegisters(instruction,
7743 temp_loc,
7744 obj_loc,
7745 class_offset,
7746 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007747 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007748
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007749 // If the class is abstract, we eagerly fetch the super class of the
7750 // object to avoid doing a comparison we know will fail.
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007751 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007752 __ Bind(&loop);
Roland Levillain3b359c72015-11-17 19:35:12 +00007753 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007754 GenerateReferenceLoadOneRegister(instruction,
7755 temp_loc,
7756 super_offset,
7757 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007758 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007759
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007760 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7761 // exception.
7762 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
Roland Levillain3b359c72015-11-17 19:35:12 +00007763
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007764 // Otherwise, compare the classes.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007765 __ cmp(temp, ShifterOperand(cls));
7766 __ b(&loop, NE);
7767 break;
7768 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007769
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007770 case TypeCheckKind::kClassHierarchyCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007771 // /* HeapReference<Class> */ temp = obj->klass_
7772 GenerateReferenceLoadTwoRegisters(instruction,
7773 temp_loc,
7774 obj_loc,
7775 class_offset,
7776 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007777 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007778
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007779 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007780 Label loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007781 __ Bind(&loop);
7782 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007783 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007784
Roland Levillain3b359c72015-11-17 19:35:12 +00007785 // /* HeapReference<Class> */ temp = temp->super_class_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007786 GenerateReferenceLoadOneRegister(instruction,
7787 temp_loc,
7788 super_offset,
7789 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007790 kWithoutReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00007791
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007792 // If the class reference currently in `temp` is null, jump to the slow path to throw the
7793 // exception.
7794 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7795 // Otherwise, jump to the beginning of the loop.
7796 __ b(&loop);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007797 break;
7798 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007799
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007800 case TypeCheckKind::kArrayObjectCheck: {
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007801 // /* HeapReference<Class> */ temp = obj->klass_
7802 GenerateReferenceLoadTwoRegisters(instruction,
7803 temp_loc,
7804 obj_loc,
7805 class_offset,
7806 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007807 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007808
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01007809 // Do an exact check.
7810 __ cmp(temp, ShifterOperand(cls));
Anton Kirilov6f644202017-02-27 18:29:45 +00007811 __ b(final_label, EQ);
Roland Levillain3b359c72015-11-17 19:35:12 +00007812
7813 // Otherwise, we need to check that the object's class is a non-primitive array.
Roland Levillain3b359c72015-11-17 19:35:12 +00007814 // /* HeapReference<Class> */ temp = temp->component_type_
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08007815 GenerateReferenceLoadOneRegister(instruction,
7816 temp_loc,
7817 component_offset,
7818 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007819 kWithoutReadBarrier);
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007820 // If the component type is null, jump to the slow path to throw the exception.
7821 __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
7822 // Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
7823 // to further check that this component type is not a primitive type.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007824 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
Roland Levillain3b359c72015-11-17 19:35:12 +00007825 static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08007826 __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007827 break;
7828 }
Roland Levillain3b359c72015-11-17 19:35:12 +00007829
Calin Juravle98893e12015-10-02 21:05:03 +01007830 case TypeCheckKind::kUnresolvedCheck:
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007831 // We always go into the type check slow path for the unresolved check case.
Roland Levillain3b359c72015-11-17 19:35:12 +00007832 // We cannot directly call the CheckCast runtime entry point
7833 // without resorting to a type checking slow path here (i.e. by
7834 // calling InvokeRuntime directly), as it would require to
7835 // assign fixed registers for the inputs of this HInstanceOf
7836 // instruction (following the runtime calling convention), which
7837 // might be cluttered by the potential first read barrier
7838 // emission at the beginning of this method.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007839
Roland Levillain3b359c72015-11-17 19:35:12 +00007840 __ b(type_check_slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007841 break;
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007842
7843 case TypeCheckKind::kInterfaceCheck: {
7844 // Avoid read barriers to improve performance of the fast path. We can not get false
7845 // positives by doing this.
7846 // /* HeapReference<Class> */ temp = obj->klass_
7847 GenerateReferenceLoadTwoRegisters(instruction,
7848 temp_loc,
7849 obj_loc,
7850 class_offset,
7851 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007852 kWithoutReadBarrier);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007853
7854 // /* HeapReference<Class> */ temp = temp->iftable_
7855 GenerateReferenceLoadTwoRegisters(instruction,
7856 temp_loc,
7857 temp_loc,
7858 iftable_offset,
7859 maybe_temp2_loc,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08007860 kWithoutReadBarrier);
Mathieu Chartier6beced42016-11-15 15:51:31 -08007861 // Iftable is never null.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007862 __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset));
Mathieu Chartier6beced42016-11-15 15:51:31 -08007863 // Loop through the iftable and check if any class matches.
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007864 Label start_loop;
7865 __ Bind(&start_loop);
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007866 __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(),
7867 type_check_slow_path->GetEntryLabel());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007868 __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset));
7869 __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>());
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007870 // Go to next interface.
7871 __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize));
7872 __ sub(maybe_temp2_loc.AsRegister<Register>(),
7873 maybe_temp2_loc.AsRegister<Register>(),
7874 ShifterOperand(2));
Mathieu Chartierafbcdaf2016-11-14 10:50:29 -08007875 // Compare the classes and continue the loop if they do not match.
7876 __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>()));
7877 __ b(&start_loop, NE);
Mathieu Chartier5c44c1b2016-11-04 18:13:04 -07007878 break;
7879 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007880 }
Anton Kirilov6f644202017-02-27 18:29:45 +00007881
7882 if (done.IsLinked()) {
7883 __ Bind(&done);
7884 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00007885
Roland Levillain3b359c72015-11-17 19:35:12 +00007886 __ Bind(type_check_slow_path->GetExitLabel());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00007887}
7888
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007889void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
7890 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01007891 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007892 InvokeRuntimeCallingConvention calling_convention;
7893 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7894}
7895
7896void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) {
Serban Constantinescu4bb30ac2016-06-22 17:04:45 +01007897 codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
7898 instruction,
7899 instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00007900 if (instruction->IsEnter()) {
7901 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
7902 } else {
7903 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
7904 }
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00007905}
7906
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007907void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
7908void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
7909void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007910
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007911void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007912 LocationSummary* locations =
7913 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7914 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7915 || instruction->GetResultType() == Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007916 // Note: GVN reorders commutative operations to have the constant on the right hand side.
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007917 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01007918 locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
Nicolas Geoffray829280c2015-01-28 10:20:37 +00007919 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00007920}
7921
7922void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
7923 HandleBitwiseOperation(instruction);
7924}
7925
7926void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
7927 HandleBitwiseOperation(instruction);
7928}
7929
7930void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
7931 HandleBitwiseOperation(instruction);
7932}
7933
Artem Serov7fc63502016-02-09 17:15:29 +00007934
7935void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7936 LocationSummary* locations =
7937 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7938 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
7939 || instruction->GetResultType() == Primitive::kPrimLong);
7940
7941 locations->SetInAt(0, Location::RequiresRegister());
7942 locations->SetInAt(1, Location::RequiresRegister());
7943 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7944}
7945
7946void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) {
7947 LocationSummary* locations = instruction->GetLocations();
7948 Location first = locations->InAt(0);
7949 Location second = locations->InAt(1);
7950 Location out = locations->Out();
7951
7952 if (instruction->GetResultType() == Primitive::kPrimInt) {
7953 Register first_reg = first.AsRegister<Register>();
7954 ShifterOperand second_reg(second.AsRegister<Register>());
7955 Register out_reg = out.AsRegister<Register>();
7956
7957 switch (instruction->GetOpKind()) {
7958 case HInstruction::kAnd:
7959 __ bic(out_reg, first_reg, second_reg);
7960 break;
7961 case HInstruction::kOr:
7962 __ orn(out_reg, first_reg, second_reg);
7963 break;
7964 // There is no EON on arm.
7965 case HInstruction::kXor:
7966 default:
7967 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7968 UNREACHABLE();
7969 }
7970 return;
7971
7972 } else {
7973 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
7974 Register first_low = first.AsRegisterPairLow<Register>();
7975 Register first_high = first.AsRegisterPairHigh<Register>();
7976 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
7977 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
7978 Register out_low = out.AsRegisterPairLow<Register>();
7979 Register out_high = out.AsRegisterPairHigh<Register>();
7980
7981 switch (instruction->GetOpKind()) {
7982 case HInstruction::kAnd:
7983 __ bic(out_low, first_low, second_low);
7984 __ bic(out_high, first_high, second_high);
7985 break;
7986 case HInstruction::kOr:
7987 __ orn(out_low, first_low, second_low);
7988 __ orn(out_high, first_high, second_high);
7989 break;
7990 // There is no EON on arm.
7991 case HInstruction::kXor:
7992 default:
7993 LOG(FATAL) << "Unexpected instruction " << instruction->DebugName();
7994 UNREACHABLE();
7995 }
7996 }
7997}
7998
Anton Kirilov74234da2017-01-13 14:42:47 +00007999void LocationsBuilderARM::VisitDataProcWithShifterOp(
8000 HDataProcWithShifterOp* instruction) {
8001 DCHECK(instruction->GetType() == Primitive::kPrimInt ||
8002 instruction->GetType() == Primitive::kPrimLong);
8003 LocationSummary* locations =
8004 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
8005 const bool overlap = instruction->GetType() == Primitive::kPrimLong &&
8006 HDataProcWithShifterOp::IsExtensionOp(instruction->GetOpKind());
8007
8008 locations->SetInAt(0, Location::RequiresRegister());
8009 locations->SetInAt(1, Location::RequiresRegister());
8010 locations->SetOut(Location::RequiresRegister(),
8011 overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap);
8012}
8013
8014void InstructionCodeGeneratorARM::VisitDataProcWithShifterOp(
8015 HDataProcWithShifterOp* instruction) {
8016 const LocationSummary* const locations = instruction->GetLocations();
8017 const HInstruction::InstructionKind kind = instruction->GetInstrKind();
8018 const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
8019 const Location left = locations->InAt(0);
8020 const Location right = locations->InAt(1);
8021 const Location out = locations->Out();
8022
8023 if (instruction->GetType() == Primitive::kPrimInt) {
8024 DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
8025
8026 const Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
8027 ? right.AsRegisterPairLow<Register>()
8028 : right.AsRegister<Register>();
8029
8030 GenerateDataProcInstruction(kind,
8031 out.AsRegister<Register>(),
8032 left.AsRegister<Register>(),
8033 ShifterOperand(second,
8034 ShiftFromOpKind(op_kind),
8035 instruction->GetShiftAmount()),
8036 codegen_);
8037 } else {
8038 DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
8039
8040 if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
8041 const Register second = right.AsRegister<Register>();
8042
8043 DCHECK_NE(out.AsRegisterPairLow<Register>(), second);
8044 GenerateDataProc(kind,
8045 out,
8046 left,
8047 ShifterOperand(second),
8048 ShifterOperand(second, ASR, 31),
8049 codegen_);
8050 } else {
8051 GenerateLongDataProc(instruction, codegen_);
8052 }
8053 }
8054}
8055
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008056void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
8057 // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
8058 if (value == 0xffffffffu) {
8059 if (out != first) {
8060 __ mov(out, ShifterOperand(first));
8061 }
8062 return;
8063 }
8064 if (value == 0u) {
8065 __ mov(out, ShifterOperand(0));
8066 return;
8067 }
8068 ShifterOperand so;
8069 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
8070 __ and_(out, first, so);
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00008071 } else if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so)) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008072 __ bic(out, first, ShifterOperand(~value));
Anton Kiriloveffd5bf2017-02-28 16:59:15 +00008073 } else {
8074 DCHECK(IsPowerOfTwo(value + 1));
8075 __ ubfx(out, first, 0, WhichPowerOf2(value + 1));
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008076 }
8077}
8078
8079void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
8080 // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
8081 if (value == 0u) {
8082 if (out != first) {
8083 __ mov(out, ShifterOperand(first));
8084 }
8085 return;
8086 }
8087 if (value == 0xffffffffu) {
8088 __ mvn(out, ShifterOperand(0));
8089 return;
8090 }
8091 ShifterOperand so;
8092 if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
8093 __ orr(out, first, so);
8094 } else {
8095 DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
8096 __ orn(out, first, ShifterOperand(~value));
8097 }
8098}
8099
8100void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
8101 // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
8102 if (value == 0u) {
8103 if (out != first) {
8104 __ mov(out, ShifterOperand(first));
8105 }
8106 return;
8107 }
8108 __ eor(out, first, ShifterOperand(value));
8109}
8110
Vladimir Marko59751a72016-08-05 14:37:27 +01008111void InstructionCodeGeneratorARM::GenerateAddLongConst(Location out,
8112 Location first,
8113 uint64_t value) {
8114 Register out_low = out.AsRegisterPairLow<Register>();
8115 Register out_high = out.AsRegisterPairHigh<Register>();
8116 Register first_low = first.AsRegisterPairLow<Register>();
8117 Register first_high = first.AsRegisterPairHigh<Register>();
8118 uint32_t value_low = Low32Bits(value);
8119 uint32_t value_high = High32Bits(value);
8120 if (value_low == 0u) {
8121 if (out_low != first_low) {
8122 __ mov(out_low, ShifterOperand(first_low));
8123 }
8124 __ AddConstant(out_high, first_high, value_high);
8125 return;
8126 }
8127 __ AddConstantSetFlags(out_low, first_low, value_low);
8128 ShifterOperand so;
8129 if (__ ShifterOperandCanHold(out_high, first_high, ADC, value_high, kCcDontCare, &so)) {
8130 __ adc(out_high, first_high, so);
8131 } else if (__ ShifterOperandCanHold(out_low, first_low, SBC, ~value_high, kCcDontCare, &so)) {
8132 __ sbc(out_high, first_high, so);
8133 } else {
8134 LOG(FATAL) << "Unexpected constant " << value_high;
8135 UNREACHABLE();
8136 }
8137}
8138
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008139void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
8140 LocationSummary* locations = instruction->GetLocations();
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008141 Location first = locations->InAt(0);
8142 Location second = locations->InAt(1);
8143 Location out = locations->Out();
8144
8145 if (second.IsConstant()) {
8146 uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
8147 uint32_t value_low = Low32Bits(value);
8148 if (instruction->GetResultType() == Primitive::kPrimInt) {
8149 Register first_reg = first.AsRegister<Register>();
8150 Register out_reg = out.AsRegister<Register>();
8151 if (instruction->IsAnd()) {
8152 GenerateAndConst(out_reg, first_reg, value_low);
8153 } else if (instruction->IsOr()) {
8154 GenerateOrrConst(out_reg, first_reg, value_low);
8155 } else {
8156 DCHECK(instruction->IsXor());
8157 GenerateEorConst(out_reg, first_reg, value_low);
8158 }
8159 } else {
8160 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
8161 uint32_t value_high = High32Bits(value);
8162 Register first_low = first.AsRegisterPairLow<Register>();
8163 Register first_high = first.AsRegisterPairHigh<Register>();
8164 Register out_low = out.AsRegisterPairLow<Register>();
8165 Register out_high = out.AsRegisterPairHigh<Register>();
8166 if (instruction->IsAnd()) {
8167 GenerateAndConst(out_low, first_low, value_low);
8168 GenerateAndConst(out_high, first_high, value_high);
8169 } else if (instruction->IsOr()) {
8170 GenerateOrrConst(out_low, first_low, value_low);
8171 GenerateOrrConst(out_high, first_high, value_high);
8172 } else {
8173 DCHECK(instruction->IsXor());
8174 GenerateEorConst(out_low, first_low, value_low);
8175 GenerateEorConst(out_high, first_high, value_high);
8176 }
8177 }
8178 return;
8179 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008180
8181 if (instruction->GetResultType() == Primitive::kPrimInt) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008182 Register first_reg = first.AsRegister<Register>();
8183 ShifterOperand second_reg(second.AsRegister<Register>());
8184 Register out_reg = out.AsRegister<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008185 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008186 __ and_(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008187 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008188 __ orr(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008189 } else {
8190 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008191 __ eor(out_reg, first_reg, second_reg);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008192 }
8193 } else {
8194 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008195 Register first_low = first.AsRegisterPairLow<Register>();
8196 Register first_high = first.AsRegisterPairHigh<Register>();
8197 ShifterOperand second_low(second.AsRegisterPairLow<Register>());
8198 ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
8199 Register out_low = out.AsRegisterPairLow<Register>();
8200 Register out_high = out.AsRegisterPairHigh<Register>();
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008201 if (instruction->IsAnd()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008202 __ and_(out_low, first_low, second_low);
8203 __ and_(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008204 } else if (instruction->IsOr()) {
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008205 __ orr(out_low, first_low, second_low);
8206 __ orr(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008207 } else {
8208 DCHECK(instruction->IsXor());
Vladimir Markod2b4ca22015-09-14 15:13:26 +01008209 __ eor(out_low, first_low, second_low);
8210 __ eor(out_high, first_high, second_high);
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00008211 }
8212 }
8213}
8214
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008215void InstructionCodeGeneratorARM::GenerateReferenceLoadOneRegister(
8216 HInstruction* instruction,
8217 Location out,
8218 uint32_t offset,
8219 Location maybe_temp,
8220 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00008221 Register out_reg = out.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008222 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08008223 CHECK(kEmitCompilerReadBarrier);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008224 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00008225 if (kUseBakerReadBarrier) {
8226 // Load with fast path based Baker's read barrier.
8227 // /* HeapReference<Object> */ out = *(out + offset)
8228 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008229 instruction, out, out_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00008230 } else {
8231 // Load with slow path based read barrier.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008232 // Save the value of `out` into `maybe_temp` before overwriting it
Roland Levillainc9285912015-12-18 10:38:42 +00008233 // in the following move operation, as we will need it for the
8234 // read barrier below.
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008235 __ Mov(maybe_temp.AsRegister<Register>(), out_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00008236 // /* HeapReference<Object> */ out = *(out + offset)
8237 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008238 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
Roland Levillainc9285912015-12-18 10:38:42 +00008239 }
8240 } else {
8241 // Plain load with no read barrier.
8242 // /* HeapReference<Object> */ out = *(out + offset)
8243 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
8244 __ MaybeUnpoisonHeapReference(out_reg);
8245 }
8246}
8247
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008248void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(
8249 HInstruction* instruction,
8250 Location out,
8251 Location obj,
8252 uint32_t offset,
8253 Location maybe_temp,
8254 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00008255 Register out_reg = out.AsRegister<Register>();
8256 Register obj_reg = obj.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008257 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartieraa474eb2016-11-09 15:18:27 -08008258 CHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00008259 if (kUseBakerReadBarrier) {
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008260 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
Roland Levillainc9285912015-12-18 10:38:42 +00008261 // Load with fast path based Baker's read barrier.
8262 // /* HeapReference<Object> */ out = *(obj + offset)
8263 codegen_->GenerateFieldLoadWithBakerReadBarrier(
Roland Levillain95e7ffc2016-01-22 11:57:25 +00008264 instruction, out, obj_reg, offset, maybe_temp, /* needs_null_check */ false);
Roland Levillainc9285912015-12-18 10:38:42 +00008265 } else {
8266 // Load with slow path based read barrier.
8267 // /* HeapReference<Object> */ out = *(obj + offset)
8268 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
8269 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
8270 }
8271 } else {
8272 // Plain load with no read barrier.
8273 // /* HeapReference<Object> */ out = *(obj + offset)
8274 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
8275 __ MaybeUnpoisonHeapReference(out_reg);
8276 }
8277}
8278
8279void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
8280 Location root,
8281 Register obj,
Mathieu Chartier31b12e32016-09-02 17:11:57 -07008282 uint32_t offset,
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008283 ReadBarrierOption read_barrier_option) {
Roland Levillainc9285912015-12-18 10:38:42 +00008284 Register root_reg = root.AsRegister<Register>();
Mathieu Chartier3af00dc2016-11-10 11:25:57 -08008285 if (read_barrier_option == kWithReadBarrier) {
Mathieu Chartier31b12e32016-09-02 17:11:57 -07008286 DCHECK(kEmitCompilerReadBarrier);
Roland Levillainc9285912015-12-18 10:38:42 +00008287 if (kUseBakerReadBarrier) {
8288 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
Roland Levillainba650a42017-03-06 13:52:32 +00008289 // Baker's read barrier are used.
Roland Levillainc9285912015-12-18 10:38:42 +00008290 //
Roland Levillainba650a42017-03-06 13:52:32 +00008291 // Note that we do not actually check the value of
8292 // `GetIsGcMarking()` to decide whether to mark the loaded GC
8293 // root or not. Instead, we load into `temp` the read barrier
8294 // mark entry point corresponding to register `root`. If `temp`
8295 // is null, it means that `GetIsGcMarking()` is false, and vice
8296 // versa.
8297 //
Mathieu Chartierfe814e82016-11-09 14:32:49 -08008298 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
Roland Levillainba650a42017-03-06 13:52:32 +00008299 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
8300 // if (temp != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8301 // // Slow path.
8302 // root = temp(root); // root = ReadBarrier::Mark(root); // Runtime entry point call.
Roland Levillainc9285912015-12-18 10:38:42 +00008303 // }
8304
Roland Levillainba650a42017-03-06 13:52:32 +00008305 // Slow path marking the GC root `root`. The entrypoint will already be loaded in `temp`.
8306 Location temp = Location::RegisterLocation(LR);
8307 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(
8308 instruction, root, /* entrypoint */ temp);
8309 codegen_->AddSlowPath(slow_path);
8310
8311 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
8312 const int32_t entry_point_offset =
8313 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(root.reg());
8314 // Loading the entrypoint does not require a load acquire since it is only changed when
8315 // threads are suspended or running a checkpoint.
8316 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
8317
Roland Levillainc9285912015-12-18 10:38:42 +00008318 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
8319 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8320 static_assert(
8321 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
8322 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
8323 "have different sizes.");
8324 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
8325 "art::mirror::CompressedReference<mirror::Object> and int32_t "
8326 "have different sizes.");
8327
Mathieu Chartierfe814e82016-11-09 14:32:49 -08008328 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8329 // checking GetIsGcMarking.
8330 __ CompareAndBranchIfNonZero(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillainc9285912015-12-18 10:38:42 +00008331 __ Bind(slow_path->GetExitLabel());
8332 } else {
8333 // GC root loaded through a slow path for read barriers other
8334 // than Baker's.
8335 // /* GcRoot<mirror::Object>* */ root = obj + offset
8336 __ AddConstant(root_reg, obj, offset);
8337 // /* mirror::Object* */ root = root->Read()
8338 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
8339 }
8340 } else {
8341 // Plain GC root load with no read barrier.
8342 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
8343 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
8344 // Note that GC roots are not affected by heap poisoning, thus we
8345 // do not have to unpoison `root_reg` here.
8346 }
8347}
8348
8349void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
8350 Location ref,
8351 Register obj,
8352 uint32_t offset,
8353 Location temp,
8354 bool needs_null_check) {
8355 DCHECK(kEmitCompilerReadBarrier);
8356 DCHECK(kUseBakerReadBarrier);
8357
8358 // /* HeapReference<Object> */ ref = *(obj + offset)
8359 Location no_index = Location::NoLocation();
Roland Levillainbfea3352016-06-23 13:48:47 +01008360 ScaleFactor no_scale_factor = TIMES_1;
Roland Levillainc9285912015-12-18 10:38:42 +00008361 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008362 instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008363}
8364
8365void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
8366 Location ref,
8367 Register obj,
8368 uint32_t data_offset,
8369 Location index,
8370 Location temp,
8371 bool needs_null_check) {
8372 DCHECK(kEmitCompilerReadBarrier);
8373 DCHECK(kUseBakerReadBarrier);
8374
Roland Levillainbfea3352016-06-23 13:48:47 +01008375 static_assert(
8376 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
8377 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Roland Levillainc9285912015-12-18 10:38:42 +00008378 // /* HeapReference<Object> */ ref =
8379 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Roland Levillainbfea3352016-06-23 13:48:47 +01008380 ScaleFactor scale_factor = TIMES_4;
Roland Levillainc9285912015-12-18 10:38:42 +00008381 GenerateReferenceLoadWithBakerReadBarrier(
Roland Levillainbfea3352016-06-23 13:48:47 +01008382 instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
Roland Levillainc9285912015-12-18 10:38:42 +00008383}
8384
8385void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
8386 Location ref,
8387 Register obj,
8388 uint32_t offset,
8389 Location index,
Roland Levillainbfea3352016-06-23 13:48:47 +01008390 ScaleFactor scale_factor,
Roland Levillainc9285912015-12-18 10:38:42 +00008391 Location temp,
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008392 bool needs_null_check,
8393 bool always_update_field,
8394 Register* temp2) {
Roland Levillainc9285912015-12-18 10:38:42 +00008395 DCHECK(kEmitCompilerReadBarrier);
8396 DCHECK(kUseBakerReadBarrier);
8397
Roland Levillain54f869e2017-03-06 13:54:11 +00008398 // Query `art::Thread::Current()->GetIsGcMarking()` to decide
8399 // whether we need to enter the slow path to mark the reference.
8400 // Then, in the slow path, check the gray bit in the lock word of
8401 // the reference's holder (`obj`) to decide whether to mark `ref` or
8402 // not.
Roland Levillainc9285912015-12-18 10:38:42 +00008403 //
Roland Levillainba650a42017-03-06 13:52:32 +00008404 // Note that we do not actually check the value of `GetIsGcMarking()`;
8405 // instead, we load into `temp3` the read barrier mark entry point
8406 // corresponding to register `ref`. If `temp3` is null, it means
8407 // that `GetIsGcMarking()` is false, and vice versa.
8408 //
8409 // temp3 = Thread::Current()->pReadBarrierMarkReg ## root.reg()
Roland Levillainba650a42017-03-06 13:52:32 +00008410 // if (temp3 != nullptr) { // <=> Thread::Current()->GetIsGcMarking()
8411 // // Slow path.
Roland Levillain54f869e2017-03-06 13:54:11 +00008412 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
8413 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
8414 // HeapReference<mirror::Object> ref = *src; // Original reference load.
8415 // bool is_gray = (rb_state == ReadBarrier::GrayState());
8416 // if (is_gray) {
8417 // ref = temp3(ref); // ref = ReadBarrier::Mark(ref); // Runtime entry point call.
8418 // }
8419 // } else {
8420 // HeapReference<mirror::Object> ref = *src; // Original reference load.
Roland Levillainc9285912015-12-18 10:38:42 +00008421 // }
Roland Levillainc9285912015-12-18 10:38:42 +00008422
Roland Levillain35345a52017-02-27 14:32:08 +00008423 Register temp_reg = temp.AsRegister<Register>();
Roland Levillain1372c9f2017-01-13 11:47:39 +00008424
Roland Levillainba650a42017-03-06 13:52:32 +00008425 // Slow path marking the object `ref` when the GC is marking. The
8426 // entrypoint will already be loaded in `temp3`.
8427 Location temp3 = Location::RegisterLocation(LR);
8428 SlowPathCodeARM* slow_path;
8429 if (always_update_field) {
8430 DCHECK(temp2 != nullptr);
Roland Levillain54f869e2017-03-06 13:54:11 +00008431 // LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM only
8432 // supports address of the form `obj + field_offset`, where `obj`
8433 // is a register and `field_offset` is a register pair (of which
8434 // only the lower half is used). Thus `offset` and `scale_factor`
8435 // above are expected to be null in this code path.
Roland Levillainba650a42017-03-06 13:52:32 +00008436 DCHECK_EQ(offset, 0u);
8437 DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
Roland Levillain54f869e2017-03-06 13:54:11 +00008438 Location field_offset = index;
8439 slow_path =
8440 new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARM(
8441 instruction,
8442 ref,
8443 obj,
8444 offset,
8445 /* index */ field_offset,
8446 scale_factor,
8447 needs_null_check,
8448 temp_reg,
8449 *temp2,
8450 /* entrypoint */ temp3);
Roland Levillainba650a42017-03-06 13:52:32 +00008451 } else {
Roland Levillain54f869e2017-03-06 13:54:11 +00008452 slow_path = new (GetGraph()->GetArena()) LoadReferenceWithBakerReadBarrierSlowPathARM(
8453 instruction,
8454 ref,
8455 obj,
8456 offset,
8457 index,
8458 scale_factor,
8459 needs_null_check,
8460 temp_reg,
8461 /* entrypoint */ temp3);
Roland Levillain35345a52017-02-27 14:32:08 +00008462 }
Roland Levillainba650a42017-03-06 13:52:32 +00008463 AddSlowPath(slow_path);
Roland Levillain35345a52017-02-27 14:32:08 +00008464
Roland Levillainba650a42017-03-06 13:52:32 +00008465 // temp3 = Thread::Current()->pReadBarrierMarkReg ## ref.reg()
8466 const int32_t entry_point_offset =
8467 CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmPointerSize>(ref.reg());
8468 // Loading the entrypoint does not require a load acquire since it is only changed when
8469 // threads are suspended or running a checkpoint.
8470 __ LoadFromOffset(kLoadWord, temp3.AsRegister<Register>(), TR, entry_point_offset);
Roland Levillainba650a42017-03-06 13:52:32 +00008471 // The entrypoint is null when the GC is not marking, this prevents one load compared to
8472 // checking GetIsGcMarking.
8473 __ CompareAndBranchIfNonZero(temp3.AsRegister<Register>(), slow_path->GetEntryLabel());
Roland Levillain54f869e2017-03-06 13:54:11 +00008474 // Fast path: just load the reference.
8475 GenerateRawReferenceLoad(instruction, ref, obj, offset, index, scale_factor, needs_null_check);
Roland Levillainba650a42017-03-06 13:52:32 +00008476 __ Bind(slow_path->GetExitLabel());
8477}
Roland Levillain35345a52017-02-27 14:32:08 +00008478
Roland Levillainba650a42017-03-06 13:52:32 +00008479void CodeGeneratorARM::GenerateRawReferenceLoad(HInstruction* instruction,
8480 Location ref,
8481 Register obj,
8482 uint32_t offset,
8483 Location index,
8484 ScaleFactor scale_factor,
8485 bool needs_null_check) {
8486 Register ref_reg = ref.AsRegister<Register>();
8487
Roland Levillainc9285912015-12-18 10:38:42 +00008488 if (index.IsValid()) {
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008489 // Load types involving an "index": ArrayGet,
8490 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8491 // intrinsics.
Roland Levillainba650a42017-03-06 13:52:32 +00008492 // /* HeapReference<mirror::Object> */ ref = *(obj + offset + (index << scale_factor))
Roland Levillainc9285912015-12-18 10:38:42 +00008493 if (index.IsConstant()) {
8494 size_t computed_offset =
Roland Levillainbfea3352016-06-23 13:48:47 +01008495 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
Roland Levillainc9285912015-12-18 10:38:42 +00008496 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
8497 } else {
Roland Levillainbfea3352016-06-23 13:48:47 +01008498 // Handle the special case of the
Roland Levillaina1aa3b12016-10-26 13:03:38 +01008499 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
8500 // intrinsics, which use a register pair as index ("long
8501 // offset"), of which only the low part contains data.
Roland Levillainbfea3352016-06-23 13:48:47 +01008502 Register index_reg = index.IsRegisterPair()
8503 ? index.AsRegisterPairLow<Register>()
8504 : index.AsRegister<Register>();
8505 __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
Roland Levillainc9285912015-12-18 10:38:42 +00008506 __ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
8507 }
8508 } else {
Roland Levillainba650a42017-03-06 13:52:32 +00008509 // /* HeapReference<mirror::Object> */ ref = *(obj + offset)
Roland Levillainc9285912015-12-18 10:38:42 +00008510 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
8511 }
8512
Roland Levillainba650a42017-03-06 13:52:32 +00008513 if (needs_null_check) {
8514 MaybeRecordImplicitNullCheck(instruction);
8515 }
8516
Roland Levillainc9285912015-12-18 10:38:42 +00008517 // Object* ref = ref_addr->AsMirrorPtr()
8518 __ MaybeUnpoisonHeapReference(ref_reg);
Roland Levillainc9285912015-12-18 10:38:42 +00008519}
8520
8521void CodeGeneratorARM::GenerateReadBarrierSlow(HInstruction* instruction,
8522 Location out,
8523 Location ref,
8524 Location obj,
8525 uint32_t offset,
8526 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008527 DCHECK(kEmitCompilerReadBarrier);
8528
Roland Levillainc9285912015-12-18 10:38:42 +00008529 // Insert a slow path based read barrier *after* the reference load.
8530 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008531 // If heap poisoning is enabled, the unpoisoning of the loaded
8532 // reference will be carried out by the runtime within the slow
8533 // path.
8534 //
8535 // Note that `ref` currently does not get unpoisoned (when heap
8536 // poisoning is enabled), which is alright as the `ref` argument is
8537 // not used by the artReadBarrierSlow entry point.
8538 //
8539 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008540 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena())
Roland Levillain3b359c72015-11-17 19:35:12 +00008541 ReadBarrierForHeapReferenceSlowPathARM(instruction, out, ref, obj, offset, index);
8542 AddSlowPath(slow_path);
8543
Roland Levillain3b359c72015-11-17 19:35:12 +00008544 __ b(slow_path->GetEntryLabel());
8545 __ Bind(slow_path->GetExitLabel());
8546}
8547
Roland Levillainc9285912015-12-18 10:38:42 +00008548void CodeGeneratorARM::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
8549 Location out,
8550 Location ref,
8551 Location obj,
8552 uint32_t offset,
8553 Location index) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008554 if (kEmitCompilerReadBarrier) {
Roland Levillainc9285912015-12-18 10:38:42 +00008555 // Baker's read barriers shall be handled by the fast path
8556 // (CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier).
8557 DCHECK(!kUseBakerReadBarrier);
Roland Levillain3b359c72015-11-17 19:35:12 +00008558 // If heap poisoning is enabled, unpoisoning will be taken care of
8559 // by the runtime within the slow path.
Roland Levillainc9285912015-12-18 10:38:42 +00008560 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
Roland Levillain3b359c72015-11-17 19:35:12 +00008561 } else if (kPoisonHeapReferences) {
8562 __ UnpoisonHeapReference(out.AsRegister<Register>());
8563 }
8564}
8565
Roland Levillainc9285912015-12-18 10:38:42 +00008566void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction,
8567 Location out,
8568 Location root) {
Roland Levillain3b359c72015-11-17 19:35:12 +00008569 DCHECK(kEmitCompilerReadBarrier);
8570
Roland Levillainc9285912015-12-18 10:38:42 +00008571 // Insert a slow path based read barrier *after* the GC root load.
8572 //
Roland Levillain3b359c72015-11-17 19:35:12 +00008573 // Note that GC roots are not affected by heap poisoning, so we do
8574 // not need to do anything special for this here.
Artem Serovf4d6aee2016-07-11 10:41:45 +01008575 SlowPathCodeARM* slow_path =
Roland Levillain3b359c72015-11-17 19:35:12 +00008576 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathARM(instruction, out, root);
8577 AddSlowPath(slow_path);
8578
Roland Levillain3b359c72015-11-17 19:35:12 +00008579 __ b(slow_path->GetEntryLabel());
8580 __ Bind(slow_path->GetExitLabel());
8581}
8582
Vladimir Markodc151b22015-10-15 18:02:30 +01008583HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
8584 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffrayc1a42cf2016-12-18 15:52:36 +00008585 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Nicolas Geoffraye807ff72017-01-23 09:03:12 +00008586 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01008587}
8588
Vladimir Markob4536b72015-11-24 13:45:23 +00008589Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
8590 Register temp) {
8591 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
8592 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
8593 if (!invoke->GetLocations()->Intrinsified()) {
8594 return location.AsRegister<Register>();
8595 }
8596 // For intrinsics we allow any location, so it may be on the stack.
8597 if (!location.IsRegister()) {
8598 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
8599 return temp;
8600 }
8601 // For register locations, check if the register was saved. If so, get it from the stack.
8602 // Note: There is a chance that the register was saved but not overwritten, so we could
8603 // save one load. However, since this is just an intrinsic slow path we prefer this
8604 // simple and more robust approach rather that trying to determine if that's the case.
8605 SlowPathCode* slow_path = GetCurrentSlowPath();
TatWai Chongd8c052a2016-11-02 16:12:48 +08008606 if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
Vladimir Markob4536b72015-11-24 13:45:23 +00008607 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
8608 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
8609 return temp;
8610 }
8611 return location.AsRegister<Register>();
8612}
8613
TatWai Chongd8c052a2016-11-02 16:12:48 +08008614Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
8615 Location temp) {
Vladimir Marko58155012015-08-19 12:49:41 +00008616 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
8617 switch (invoke->GetMethodLoadKind()) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008618 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
8619 uint32_t offset =
8620 GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Vladimir Marko58155012015-08-19 12:49:41 +00008621 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008622 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
Vladimir Marko58155012015-08-19 12:49:41 +00008623 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01008624 }
Vladimir Marko58155012015-08-19 12:49:41 +00008625 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00008626 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00008627 break;
8628 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
8629 __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
8630 break;
Vladimir Markob4536b72015-11-24 13:45:23 +00008631 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
8632 HArmDexCacheArraysBase* base =
8633 invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
8634 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
8635 temp.AsRegister<Register>());
8636 int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
8637 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
8638 break;
8639 }
Vladimir Marko58155012015-08-19 12:49:41 +00008640 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00008641 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Vladimir Marko58155012015-08-19 12:49:41 +00008642 Register method_reg;
8643 Register reg = temp.AsRegister<Register>();
8644 if (current_method.IsRegister()) {
8645 method_reg = current_method.AsRegister<Register>();
8646 } else {
8647 DCHECK(invoke->GetLocations()->Intrinsified());
8648 DCHECK(!current_method.IsValid());
8649 method_reg = reg;
8650 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
8651 }
Roland Levillain3b359c72015-11-17 19:35:12 +00008652 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_;
8653 __ LoadFromOffset(kLoadWord,
8654 reg,
8655 method_reg,
8656 ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01008657 // temp = temp[index_in_cache];
8658 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
8659 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Vladimir Marko58155012015-08-19 12:49:41 +00008660 __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache));
8661 break;
Nicolas Geoffrayae71a052015-06-09 14:12:28 +01008662 }
Vladimir Marko58155012015-08-19 12:49:41 +00008663 }
TatWai Chongd8c052a2016-11-02 16:12:48 +08008664 return callee_method;
8665}
8666
8667void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
8668 Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp);
Vladimir Marko58155012015-08-19 12:49:41 +00008669
8670 switch (invoke->GetCodePtrLocation()) {
8671 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
8672 __ bl(GetFrameEntryLabel());
8673 break;
Vladimir Marko58155012015-08-19 12:49:41 +00008674 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
8675 // LR = callee_method->entry_point_from_quick_compiled_code_
8676 __ LoadFromOffset(
8677 kLoadWord, LR, callee_method.AsRegister<Register>(),
Andreas Gampe542451c2016-07-26 09:02:02 -07008678 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
Vladimir Marko58155012015-08-19 12:49:41 +00008679 // LR()
8680 __ blx(LR);
8681 break;
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08008682 }
8683
Andreas Gampe2bcf9bf2015-01-29 09:56:07 -08008684 DCHECK(!IsLeafMethod());
8685}
8686
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008687void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
8688 Register temp = temp_location.AsRegister<Register>();
8689 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
8690 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
Nicolas Geoffraye5234232015-12-02 09:06:11 +00008691
8692 // Use the calling convention instead of the location of the receiver, as
8693 // intrinsics may have put the receiver in a different register. In the intrinsics
8694 // slow path, the arguments have been moved to the right place, so here we are
8695 // guaranteed that the receiver is the first register of the calling convention.
8696 InvokeDexCallingConvention calling_convention;
8697 Register receiver = calling_convention.GetRegisterAt(0);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008698 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Roland Levillain3b359c72015-11-17 19:35:12 +00008699 // /* HeapReference<Class> */ temp = receiver->klass_
Nicolas Geoffraye5234232015-12-02 09:06:11 +00008700 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008701 MaybeRecordImplicitNullCheck(invoke);
Roland Levillain3b359c72015-11-17 19:35:12 +00008702 // Instead of simply (possibly) unpoisoning `temp` here, we should
8703 // emit a read barrier for the previous class reference load.
8704 // However this is not required in practice, as this is an
8705 // intermediate/temporary reference and because the current
8706 // concurrent copying collector keeps the from-space memory
8707 // intact/accessible until the end of the marking phase (the
8708 // concurrent copying collector may not in the future).
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008709 __ MaybeUnpoisonHeapReference(temp);
8710 // temp = temp->GetMethodAt(method_offset);
8711 uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07008712 kArmPointerSize).Int32Value();
Andreas Gampebfb5ba92015-09-01 15:45:02 +00008713 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
8714 // LR = temp->GetEntryPoint();
8715 __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
8716 // LR();
8717 __ blx(LR);
8718}
8719
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008720CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatch(
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008721 const DexFile& dex_file, dex::StringIndex string_index) {
8722 return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008723}
8724
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008725CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
Andreas Gampea5b09a62016-11-17 15:21:22 -08008726 const DexFile& dex_file, dex::TypeIndex type_index) {
8727 return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008728}
8729
Vladimir Marko1998cd02017-01-13 13:02:58 +00008730CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewTypeBssEntryPatch(
8731 const DexFile& dex_file, dex::TypeIndex type_index) {
8732 return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
8733}
8734
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008735CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
8736 const DexFile& dex_file, uint32_t element_offset) {
8737 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
8738}
8739
8740CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
8741 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
8742 patches->emplace_back(dex_file, offset_or_index);
8743 return &patches->back();
8744}
8745
8746Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008747 dex::StringIndex string_index) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008748 return boot_image_string_patches_.GetOrCreate(
8749 StringReference(&dex_file, string_index),
8750 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8751}
8752
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008753Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08008754 dex::TypeIndex type_index) {
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008755 return boot_image_type_patches_.GetOrCreate(
8756 TypeReference(&dex_file, type_index),
8757 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8758}
8759
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008760Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) {
Richard Uhlerc52f3032017-03-02 13:45:45 +00008761 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008762}
8763
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008764Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00008765 dex::StringIndex string_index,
8766 Handle<mirror::String> handle) {
8767 jit_string_roots_.Overwrite(StringReference(&dex_file, string_index),
8768 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray132d8362016-11-16 09:19:42 +00008769 return jit_string_patches_.GetOrCreate(
8770 StringReference(&dex_file, string_index),
8771 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8772}
8773
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008774Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
8775 dex::TypeIndex type_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +00008776 Handle<mirror::Class> handle) {
8777 jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index),
8778 reinterpret_cast64<uint64_t>(handle.GetReference()));
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008779 return jit_class_patches_.GetOrCreate(
8780 TypeReference(&dex_file, type_index),
8781 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
8782}
8783
Vladimir Markoaad75c62016-10-03 08:46:48 +00008784template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
8785inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
8786 const ArenaDeque<PcRelativePatchInfo>& infos,
8787 ArenaVector<LinkerPatch>* linker_patches) {
8788 for (const PcRelativePatchInfo& info : infos) {
8789 const DexFile& dex_file = info.target_dex_file;
8790 size_t offset_or_index = info.offset_or_index;
8791 DCHECK(info.add_pc_label.IsBound());
8792 uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
8793 // Add MOVW patch.
8794 DCHECK(info.movw_label.IsBound());
8795 uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
8796 linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
8797 // Add MOVT patch.
8798 DCHECK(info.movt_label.IsBound());
8799 uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
8800 linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
8801 }
8802}
8803
Vladimir Marko58155012015-08-19 12:49:41 +00008804void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
8805 DCHECK(linker_patches->empty());
Vladimir Markob4536b72015-11-24 13:45:23 +00008806 size_t size =
Vladimir Markoaad75c62016-10-03 08:46:48 +00008807 /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008808 boot_image_string_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00008809 /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008810 boot_image_type_patches_.size() +
Vladimir Markoaad75c62016-10-03 08:46:48 +00008811 /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
Richard Uhlerc52f3032017-03-02 13:45:45 +00008812 /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size();
Vladimir Marko58155012015-08-19 12:49:41 +00008813 linker_patches->reserve(size);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008814 EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
8815 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008816 for (const auto& entry : boot_image_string_patches_) {
8817 const StringReference& target_string = entry.first;
8818 Literal* literal = entry.second;
8819 DCHECK(literal->GetLabel()->IsBound());
8820 uint32_t literal_offset = literal->GetLabel()->Position();
8821 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
8822 target_string.dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008823 target_string.string_index.index_));
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008824 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00008825 if (!GetCompilerOptions().IsBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00008826 DCHECK(pc_relative_type_patches_.empty());
Vladimir Markoaad75c62016-10-03 08:46:48 +00008827 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
8828 linker_patches);
8829 } else {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008830 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
8831 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008832 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
8833 linker_patches);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008834 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00008835 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
8836 linker_patches);
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008837 for (const auto& entry : boot_image_type_patches_) {
8838 const TypeReference& target_type = entry.first;
8839 Literal* literal = entry.second;
8840 DCHECK(literal->GetLabel()->IsBound());
8841 uint32_t literal_offset = literal->GetLabel()->Position();
8842 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
8843 target_type.dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08008844 target_type.type_index.index_));
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01008845 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00008846 DCHECK_EQ(size, linker_patches->size());
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008847}
8848
8849Literal* CodeGeneratorARM::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
8850 return map->GetOrCreate(
8851 value,
8852 [this, value]() { return __ NewLiteral<uint32_t>(value); });
Vladimir Marko58155012015-08-19 12:49:41 +00008853}
8854
8855Literal* CodeGeneratorARM::DeduplicateMethodLiteral(MethodReference target_method,
8856 MethodToLiteralMap* map) {
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008857 return map->GetOrCreate(
8858 target_method,
8859 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
Vladimir Marko58155012015-08-19 12:49:41 +00008860}
8861
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03008862void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8863 LocationSummary* locations =
8864 new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall);
8865 locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex,
8866 Location::RequiresRegister());
8867 locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister());
8868 locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister());
8869 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8870}
8871
8872void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) {
8873 LocationSummary* locations = instr->GetLocations();
8874 Register res = locations->Out().AsRegister<Register>();
8875 Register accumulator =
8876 locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex).AsRegister<Register>();
8877 Register mul_left =
8878 locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex).AsRegister<Register>();
8879 Register mul_right =
8880 locations->InAt(HMultiplyAccumulate::kInputMulRightIndex).AsRegister<Register>();
8881
8882 if (instr->GetOpKind() == HInstruction::kAdd) {
8883 __ mla(res, mul_left, mul_right, accumulator);
8884 } else {
8885 __ mls(res, mul_left, mul_right, accumulator);
8886 }
8887}
8888
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008889void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008890 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008891 LOG(FATAL) << "Unreachable";
8892}
8893
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01008894void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
Calin Juravleb1498f62015-02-16 13:13:29 +00008895 // Nothing to do, this should be removed during prepare for register allocator.
Calin Juravleb1498f62015-02-16 13:13:29 +00008896 LOG(FATAL) << "Unreachable";
8897}
8898
Mark Mendellfe57faa2015-09-18 09:26:15 -04008899// Simple implementation of packed switch - generate cascaded compare/jumps.
8900void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8901 LocationSummary* locations =
8902 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
8903 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008904 if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold &&
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008905 codegen_->GetAssembler()->IsThumb()) {
8906 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base.
8907 if (switch_instr->GetStartValue() != 0) {
8908 locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias.
8909 }
8910 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04008911}
8912
8913void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) {
8914 int32_t lower_bound = switch_instr->GetStartValue();
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008915 uint32_t num_entries = switch_instr->GetNumEntries();
Mark Mendellfe57faa2015-09-18 09:26:15 -04008916 LocationSummary* locations = switch_instr->GetLocations();
8917 Register value_reg = locations->InAt(0).AsRegister<Register>();
8918 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
8919
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008920 if (num_entries <= kPackedSwitchCompareJumpThreshold || !codegen_->GetAssembler()->IsThumb()) {
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008921 // Create a series of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008922 Register temp_reg = IP;
8923 // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store
8924 // the immediate, because IP is used as the destination register. For the other
8925 // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant,
8926 // and they can be encoded in the instruction without making use of IP register.
8927 __ AddConstantSetFlags(temp_reg, value_reg, -lower_bound);
8928
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008929 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008930 // Jump to successors[0] if value == lower_bound.
8931 __ b(codegen_->GetLabelOf(successors[0]), EQ);
8932 int32_t last_index = 0;
8933 for (; num_entries - last_index > 2; last_index += 2) {
8934 __ AddConstantSetFlags(temp_reg, temp_reg, -2);
8935 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
8936 __ b(codegen_->GetLabelOf(successors[last_index + 1]), LO);
8937 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
8938 __ b(codegen_->GetLabelOf(successors[last_index + 2]), EQ);
8939 }
8940 if (num_entries - last_index == 2) {
8941 // The last missing case_value.
Vladimir Markoac6ac102015-12-17 12:14:00 +00008942 __ CmpConstant(temp_reg, 1);
Vladimir Markof3e0ee22015-12-17 15:23:13 +00008943 __ b(codegen_->GetLabelOf(successors[last_index + 1]), EQ);
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008944 }
Mark Mendellfe57faa2015-09-18 09:26:15 -04008945
Andreas Gampe7cffc3b2015-10-19 21:31:53 -07008946 // And the default for any other value.
8947 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
8948 __ b(codegen_->GetLabelOf(default_block));
8949 }
8950 } else {
8951 // Create a table lookup.
8952 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
8953
8954 // Materialize a pointer to the switch table
8955 std::vector<Label*> labels(num_entries);
8956 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
8957 for (uint32_t i = 0; i < num_entries; i++) {
8958 labels[i] = codegen_->GetLabelOf(successors[i]);
8959 }
8960 JumpTable* table = __ CreateJumpTable(std::move(labels), temp_reg);
8961
8962 // Remove the bias.
8963 Register key_reg;
8964 if (lower_bound != 0) {
8965 key_reg = locations->GetTemp(1).AsRegister<Register>();
8966 __ AddConstant(key_reg, value_reg, -lower_bound);
8967 } else {
8968 key_reg = value_reg;
8969 }
8970
8971 // Check whether the value is in the table, jump to default block if not.
8972 __ CmpConstant(key_reg, num_entries - 1);
8973 __ b(codegen_->GetLabelOf(default_block), Condition::HI);
8974
8975 // Load the displacement from the table.
8976 __ ldr(temp_reg, Address(temp_reg, key_reg, Shift::LSL, 2));
8977
8978 // Dispatch is a direct add to the PC (for Thumb2).
8979 __ EmitJumpTableDispatch(table, temp_reg);
Mark Mendellfe57faa2015-09-18 09:26:15 -04008980 }
8981}
8982
Vladimir Markob4536b72015-11-24 13:45:23 +00008983void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8984 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
8985 locations->SetOut(Location::RequiresRegister());
Vladimir Markob4536b72015-11-24 13:45:23 +00008986}
8987
8988void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
8989 Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008990 CodeGeneratorARM::PcRelativePatchInfo* labels =
8991 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Vladimir Markob4536b72015-11-24 13:45:23 +00008992 __ BindTrackedLabel(&labels->movw_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008993 __ movw(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00008994 __ BindTrackedLabel(&labels->movt_label);
Vladimir Markocac5a7e2016-02-22 10:39:50 +00008995 __ movt(base_reg, /* placeholder */ 0u);
Vladimir Markob4536b72015-11-24 13:45:23 +00008996 __ BindTrackedLabel(&labels->add_pc_label);
8997 __ add(base_reg, base_reg, ShifterOperand(PC));
8998}
8999
Andreas Gampe85b62f22015-09-09 13:15:38 -07009000void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
9001 if (!trg.IsValid()) {
Roland Levillainc9285912015-12-18 10:38:42 +00009002 DCHECK_EQ(type, Primitive::kPrimVoid);
Andreas Gampe85b62f22015-09-09 13:15:38 -07009003 return;
9004 }
9005
9006 DCHECK_NE(type, Primitive::kPrimVoid);
9007
9008 Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type);
9009 if (return_loc.Equals(trg)) {
9010 return;
9011 }
9012
9013 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
9014 // with the last branch.
9015 if (type == Primitive::kPrimLong) {
9016 HParallelMove parallel_move(GetGraph()->GetArena());
9017 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimInt, nullptr);
9018 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimInt, nullptr);
9019 GetMoveResolver()->EmitNativeCode(&parallel_move);
9020 } else if (type == Primitive::kPrimDouble) {
9021 HParallelMove parallel_move(GetGraph()->GetArena());
9022 parallel_move.AddMove(return_loc.ToLow(), trg.ToLow(), Primitive::kPrimFloat, nullptr);
9023 parallel_move.AddMove(return_loc.ToHigh(), trg.ToHigh(), Primitive::kPrimFloat, nullptr);
9024 GetMoveResolver()->EmitNativeCode(&parallel_move);
9025 } else {
9026 // Let the parallel move resolver take care of all of this.
9027 HParallelMove parallel_move(GetGraph()->GetArena());
9028 parallel_move.AddMove(return_loc, trg, type, nullptr);
9029 GetMoveResolver()->EmitNativeCode(&parallel_move);
9030 }
9031}
9032
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009033void LocationsBuilderARM::VisitClassTableGet(HClassTableGet* instruction) {
9034 LocationSummary* locations =
9035 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
9036 locations->SetInAt(0, Location::RequiresRegister());
9037 locations->SetOut(Location::RequiresRegister());
9038}
9039
9040void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
9041 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00009042 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009043 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009044 instruction->GetIndex(), kArmPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009045 __ LoadFromOffset(kLoadWord,
9046 locations->Out().AsRegister<Register>(),
9047 locations->InAt(0).AsRegister<Register>(),
9048 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009049 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009050 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00009051 instruction->GetIndex(), kArmPointerSize));
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009052 __ LoadFromOffset(kLoadWord,
9053 locations->Out().AsRegister<Register>(),
9054 locations->InAt(0).AsRegister<Register>(),
9055 mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
9056 __ LoadFromOffset(kLoadWord,
9057 locations->Out().AsRegister<Register>(),
9058 locations->Out().AsRegister<Register>(),
9059 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009060 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009061}
9062
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009063static void PatchJitRootUse(uint8_t* code,
9064 const uint8_t* roots_data,
9065 Literal* literal,
9066 uint64_t index_in_table) {
9067 DCHECK(literal->GetLabel()->IsBound());
9068 uint32_t literal_offset = literal->GetLabel()->Position();
9069 uintptr_t address =
9070 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
9071 uint8_t* data = code + literal_offset;
9072 reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
9073}
9074
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009075void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
9076 for (const auto& entry : jit_string_patches_) {
9077 const auto& it = jit_string_roots_.find(entry.first);
9078 DCHECK(it != jit_string_roots_.end());
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00009079 PatchJitRootUse(code, roots_data, entry.second, it->second);
9080 }
9081 for (const auto& entry : jit_class_patches_) {
9082 const auto& it = jit_class_roots_.find(entry.first);
9083 DCHECK(it != jit_class_roots_.end());
9084 PatchJitRootUse(code, roots_data, entry.second, it->second);
Nicolas Geoffray132d8362016-11-16 09:19:42 +00009085 }
9086}
9087
Roland Levillain4d027112015-07-01 15:41:14 +01009088#undef __
9089#undef QUICK_ENTRY_POINT
9090
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00009091} // namespace arm
9092} // namespace art