blob: b607a1db3a51a13f9d2fc24a9b0c86299318c402 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 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 */
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070016
Ian Rogers2c8f6532011-09-02 17:16:34 -070017#include "assembler_arm.h"
18
Elliott Hughes07ed66b2012-12-12 18:34:25 -080019#include "base/logging.h"
Ian Rogers166db042013-07-26 12:05:57 -070020#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070021#include "offsets.h"
Carl Shapiroe2d373e2011-07-25 15:20:06 -070022#include "thread.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070023#include "utils.h"
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070024
Carl Shapiro6b6b5f02011-06-21 15:05:09 -070025namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070026namespace arm {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070027
Dave Allison65fcc2c2014-04-28 13:45:27 -070028const char* kRegisterNames[] = {
Elliott Hughes1f359b02011-07-17 14:27:17 -070029 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
30 "fp", "ip", "sp", "lr", "pc"
31};
Dave Allison65fcc2c2014-04-28 13:45:27 -070032
33const char* kConditionNames[] = {
34 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT",
35 "LE", "AL",
36};
37
Elliott Hughes1f359b02011-07-17 14:27:17 -070038std::ostream& operator<<(std::ostream& os, const Register& rhs) {
39 if (rhs >= R0 && rhs <= PC) {
40 os << kRegisterNames[rhs];
41 } else {
Ian Rogersb033c752011-07-20 12:22:35 -070042 os << "Register[" << static_cast<int>(rhs) << "]";
Elliott Hughes1f359b02011-07-17 14:27:17 -070043 }
44 return os;
45}
46
47
48std::ostream& operator<<(std::ostream& os, const SRegister& rhs) {
49 if (rhs >= S0 && rhs < kNumberOfSRegisters) {
Ian Rogersb033c752011-07-20 12:22:35 -070050 os << "s" << static_cast<int>(rhs);
Elliott Hughes1f359b02011-07-17 14:27:17 -070051 } else {
Ian Rogersb033c752011-07-20 12:22:35 -070052 os << "SRegister[" << static_cast<int>(rhs) << "]";
Elliott Hughes1f359b02011-07-17 14:27:17 -070053 }
54 return os;
55}
56
57
58std::ostream& operator<<(std::ostream& os, const DRegister& rhs) {
59 if (rhs >= D0 && rhs < kNumberOfDRegisters) {
Ian Rogersb033c752011-07-20 12:22:35 -070060 os << "d" << static_cast<int>(rhs);
Elliott Hughes1f359b02011-07-17 14:27:17 -070061 } else {
Ian Rogersb033c752011-07-20 12:22:35 -070062 os << "DRegister[" << static_cast<int>(rhs) << "]";
Elliott Hughes1f359b02011-07-17 14:27:17 -070063 }
64 return os;
65}
66
Elliott Hughes1f359b02011-07-17 14:27:17 -070067std::ostream& operator<<(std::ostream& os, const Condition& rhs) {
68 if (rhs >= EQ && rhs <= AL) {
69 os << kConditionNames[rhs];
70 } else {
Ian Rogersb033c752011-07-20 12:22:35 -070071 os << "Condition[" << static_cast<int>(rhs) << "]";
Elliott Hughes1f359b02011-07-17 14:27:17 -070072 }
73 return os;
74}
75
Carl Shapiroa2e18e12011-06-21 18:57:55 -070076
77
Dave Allison65fcc2c2014-04-28 13:45:27 -070078uint32_t ShifterOperand::encodingArm() const {
79 CHECK(is_valid());
80 switch (type_) {
81 case kImmediate:
82 if (is_rotate_) {
83 return (rotate_ << kRotateShift) | (immed_ << kImmed8Shift);
84 } else {
85 return immed_;
Ian Rogersb033c752011-07-20 12:22:35 -070086 }
Dave Allison65fcc2c2014-04-28 13:45:27 -070087 break;
88 case kRegister:
89 if (is_shift_) {
90 // Shifted immediate or register.
91 if (rs_ == kNoRegister) {
92 // Immediate shift.
93 return immed_ << kShiftImmShift |
94 static_cast<uint32_t>(shift_) << kShiftShift |
95 static_cast<uint32_t>(rm_);
96 } else {
97 // Register shift.
98 return static_cast<uint32_t>(rs_) << kShiftRegisterShift |
99 static_cast<uint32_t>(shift_) << kShiftShift | (1 << 4) |
100 static_cast<uint32_t>(rm_);
101 }
102 } else {
103 // Simple register
104 return static_cast<uint32_t>(rm_);
Ian Rogersb033c752011-07-20 12:22:35 -0700105 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700106 break;
107 default:
108 // Can't get here.
109 LOG(FATAL) << "Invalid shifter operand for ARM";
110 return 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700111 }
112}
113
Dave Allison65fcc2c2014-04-28 13:45:27 -0700114uint32_t ShifterOperand::encodingThumb(int version) const {
115 CHECK(version == 1 || version == 2);
116 if (version == 1) {
117 LOG(FATAL) << "Invalid of use encodingThumb with version 1";
Ian Rogersb033c752011-07-20 12:22:35 -0700118 } else {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700119 switch (type_) {
120 case kImmediate:
121 return immed_;
122 case kRegister:
123 if (is_shift_) {
124 // Shifted immediate or register.
125 if (rs_ == kNoRegister) {
126 // Immediate shift.
127 if (shift_ == RRX) {
128 // RRX is encoded as an ROR with imm 0.
129 return ROR << 4 | static_cast<uint32_t>(rm_);
130 } else {
131 uint32_t imm3 = immed_ >> 2;
132 uint32_t imm2 = immed_ & 0b11;
133
134 return imm3 << 12 | imm2 << 6 | shift_ << 4 |
135 static_cast<uint32_t>(rm_);
136 }
137 } else {
138 LOG(FATAL) << "No register-shifted register instruction available in thumb";
139 return 0;
140 }
141 } else {
142 // Simple register
143 return static_cast<uint32_t>(rm_);
144 }
145 break;
146 default:
147 // Can't get here.
148 LOG(FATAL) << "Invalid shifter operand for thumb";
149 return 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700150 }
151 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700152 return 0;
153}
154
155bool ShifterOperand::CanHoldThumb(Register rd, Register rn, Opcode opcode,
156 uint32_t immediate, ShifterOperand* shifter_op) {
157 shifter_op->type_ = kImmediate;
158 shifter_op->immed_ = immediate;
159 shifter_op->is_shift_ = false;
160 shifter_op->is_rotate_ = false;
161 switch (opcode) {
162 case ADD:
163 case SUB:
164 if (rn == SP) {
165 if (rd == SP) {
166 return immediate < (1 << 9); // 9 bits allowed.
167 } else {
168 return immediate < (1 << 12); // 12 bits.
169 }
170 }
171 if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done.
172 return true;
173 }
174 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
175
176 case MOV:
177 if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done.
178 return true;
179 }
180 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
181 case MVN:
182 default:
183 return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
184 }
Ian Rogersb033c752011-07-20 12:22:35 -0700185}
186
Dave Allison65fcc2c2014-04-28 13:45:27 -0700187uint32_t Address::encodingArm() const {
188 CHECK(IsAbsoluteUint(12, offset_));
189 uint32_t encoding;
190 if (offset_ < 0) {
191 encoding = (am_ ^ (1 << kUShift)) | -offset_; // Flip U to adjust sign.
192 } else {
193 encoding = am_ | offset_;
194 }
195 encoding |= static_cast<uint32_t>(rn_) << kRnShift;
196 return encoding;
197}
Ian Rogersb033c752011-07-20 12:22:35 -0700198
Dave Allison65fcc2c2014-04-28 13:45:27 -0700199
200uint32_t Address::encodingThumb(int version) const {
201 CHECK(version == 1 || version == 2);
202 uint32_t encoding = 0;
203 if (version == 2) {
204 encoding = static_cast<uint32_t>(rn_) << 16;
205 // Check for the T3/T4 encoding.
206 // PUW must Offset for T3
207 // Convert ARM PU0W to PUW
208 // The Mode is in ARM encoding format which is:
209 // |P|U|0|W|
210 // we need this in thumb2 mode:
211 // |P|U|W|
212
213 uint32_t am = am_;
214 int32_t offset = offset_;
215 if (offset < 0) {
216 am ^= 1 << kUShift;
217 offset = -offset;
218 }
219 if (offset_ < 0 || (offset >= 0 && offset < 256 &&
220 am_ != Mode::Offset)) {
221 // T4 encoding.
222 uint32_t PUW = am >> 21; // Move down to bottom of word.
223 PUW = (PUW >> 1) | (PUW & 1); // Bits 3, 2 and 0.
224 // If P is 0 then W must be 1 (Different from ARM).
225 if ((PUW & 0b100) == 0) {
226 PUW |= 0b1;
227 }
228 encoding |= B11 | PUW << 8 | offset;
229 } else {
230 // T3 encoding (also sets op1 to 0b01).
231 encoding |= B23 | offset_;
232 }
233 } else {
234 LOG(FATAL) << "Invalid use of encodingThumb for version 1";
235 }
236 return encoding;
237}
238
239// This is very like the ARM encoding except the offset is 10 bits.
240uint32_t Address::encodingThumbLdrdStrd() const {
241 uint32_t encoding;
242 uint32_t am = am_;
243 // If P is 0 then W must be 1 (Different from ARM).
244 uint32_t PU1W = am_ >> 21; // Move down to bottom of word.
245 if ((PU1W & 0b1000) == 0) {
246 am |= 1 << 21; // Set W bit.
247 }
248 if (offset_ < 0) {
249 int32_t off = -offset_;
250 CHECK_LT(off, 1024);
251 CHECK_EQ((off & 0b11), 0); // Must be multiple of 4.
252 encoding = (am ^ (1 << kUShift)) | off >> 2; // Flip U to adjust sign.
253 } else {
254 CHECK_LT(offset_, 1024);
255 CHECK_EQ((offset_ & 0b11), 0); // Must be multiple of 4.
256 encoding = am | offset_ >> 2;
257 }
258 encoding |= static_cast<uint32_t>(rn_) << 16;
259 return encoding;
260}
261
262// Encoding for ARM addressing mode 3.
263uint32_t Address::encoding3() const {
264 const uint32_t offset_mask = (1 << 12) - 1;
265 uint32_t encoding = encodingArm();
266 uint32_t offset = encoding & offset_mask;
267 CHECK_LT(offset, 256u);
268 return (encoding & ~offset_mask) | ((offset & 0xf0) << 4) | (offset & 0xf);
269}
270
271// Encoding for vfp load/store addressing.
272uint32_t Address::vencoding() const {
273 const uint32_t offset_mask = (1 << 12) - 1;
274 uint32_t encoding = encodingArm();
275 uint32_t offset = encoding & offset_mask;
276 CHECK(IsAbsoluteUint(10, offset)); // In the range -1020 to +1020.
277 CHECK_ALIGNED(offset, 2); // Multiple of 4.
278 CHECK((am_ == Offset) || (am_ == NegOffset));
279 uint32_t vencoding = (encoding & (0xf << kRnShift)) | (offset >> 2);
280 if (am_ == Offset) {
281 vencoding |= 1 << 23;
282 }
283 return vencoding;
284}
285
286
287bool Address::CanHoldLoadOffsetArm(LoadOperandType type, int offset) {
Ian Rogersb033c752011-07-20 12:22:35 -0700288 switch (type) {
289 case kLoadSignedByte:
290 case kLoadSignedHalfword:
291 case kLoadUnsignedHalfword:
292 case kLoadWordPair:
293 return IsAbsoluteUint(8, offset); // Addressing mode 3.
294 case kLoadUnsignedByte:
295 case kLoadWord:
296 return IsAbsoluteUint(12, offset); // Addressing mode 2.
297 case kLoadSWord:
298 case kLoadDWord:
299 return IsAbsoluteUint(10, offset); // VFP addressing mode.
300 default:
301 LOG(FATAL) << "UNREACHABLE";
302 return false;
303 }
304}
305
306
Dave Allison65fcc2c2014-04-28 13:45:27 -0700307bool Address::CanHoldStoreOffsetArm(StoreOperandType type, int offset) {
Ian Rogersb033c752011-07-20 12:22:35 -0700308 switch (type) {
309 case kStoreHalfword:
310 case kStoreWordPair:
311 return IsAbsoluteUint(8, offset); // Addressing mode 3.
312 case kStoreByte:
313 case kStoreWord:
314 return IsAbsoluteUint(12, offset); // Addressing mode 2.
315 case kStoreSWord:
316 case kStoreDWord:
317 return IsAbsoluteUint(10, offset); // VFP addressing mode.
318 default:
319 LOG(FATAL) << "UNREACHABLE";
320 return false;
321 }
322}
323
Dave Allison65fcc2c2014-04-28 13:45:27 -0700324bool Address::CanHoldLoadOffsetThumb(LoadOperandType type, int offset) {
Ian Rogersb033c752011-07-20 12:22:35 -0700325 switch (type) {
326 case kLoadSignedByte:
Ian Rogersb033c752011-07-20 12:22:35 -0700327 case kLoadSignedHalfword:
Ian Rogersb033c752011-07-20 12:22:35 -0700328 case kLoadUnsignedHalfword:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700329 case kLoadUnsignedByte:
Ian Rogersb033c752011-07-20 12:22:35 -0700330 case kLoadWord:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700331 return IsAbsoluteUint(12, offset);
332 case kLoadSWord:
333 case kLoadDWord:
334 return IsAbsoluteUint(10, offset); // VFP addressing mode.
Ian Rogersb033c752011-07-20 12:22:35 -0700335 case kLoadWordPair:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700336 return IsAbsoluteUint(10, offset);
337 default:
Ian Rogersb033c752011-07-20 12:22:35 -0700338 LOG(FATAL) << "UNREACHABLE";
Dave Allison65fcc2c2014-04-28 13:45:27 -0700339 return false;
Ian Rogersb033c752011-07-20 12:22:35 -0700340 }
341}
342
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700343
Dave Allison65fcc2c2014-04-28 13:45:27 -0700344bool Address::CanHoldStoreOffsetThumb(StoreOperandType type, int offset) {
Ian Rogersb033c752011-07-20 12:22:35 -0700345 switch (type) {
Ian Rogersb033c752011-07-20 12:22:35 -0700346 case kStoreHalfword:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700347 case kStoreByte:
Ian Rogersb033c752011-07-20 12:22:35 -0700348 case kStoreWord:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700349 return IsAbsoluteUint(12, offset);
350 case kStoreSWord:
351 case kStoreDWord:
352 return IsAbsoluteUint(10, offset); // VFP addressing mode.
Ian Rogersb033c752011-07-20 12:22:35 -0700353 case kStoreWordPair:
Dave Allison65fcc2c2014-04-28 13:45:27 -0700354 return IsAbsoluteUint(10, offset);
355 default:
Ian Rogersb033c752011-07-20 12:22:35 -0700356 LOG(FATAL) << "UNREACHABLE";
Dave Allison65fcc2c2014-04-28 13:45:27 -0700357 return false;
Ian Rogersb033c752011-07-20 12:22:35 -0700358 }
359}
360
Dave Allison65fcc2c2014-04-28 13:45:27 -0700361void ArmAssembler::Pad(uint32_t bytes) {
362 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
363 for (uint32_t i = 0; i < bytes; ++i) {
364 buffer_.Emit<byte>(0);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700365 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700366}
367
Ian Rogers790a6b72014-04-01 10:36:00 -0700368constexpr size_t kFramePointerSize = 4;
369
Ian Rogers2c8f6532011-09-02 17:16:34 -0700370void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
Ian Rogersb5d09b22012-03-06 22:14:17 -0800371 const std::vector<ManagedRegister>& callee_save_regs,
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700372 const ManagedRegisterEntrySpills& entry_spills) {
Elliott Hughes06b37d92011-10-16 11:51:29 -0700373 CHECK_ALIGNED(frame_size, kStackAlignment);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700374 CHECK_EQ(R0, method_reg.AsArm().AsCoreRegister());
Ian Rogersbdb03912011-09-14 00:55:44 -0700375
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700376 // Push callee saves and link register.
Ian Rogersbdb03912011-09-14 00:55:44 -0700377 RegList push_list = 1 << LR;
378 size_t pushed_values = 1;
379 for (size_t i = 0; i < callee_save_regs.size(); i++) {
380 Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister();
381 push_list |= 1 << reg;
382 pushed_values++;
Ian Rogers0d666d82011-08-14 16:03:46 -0700383 }
Ian Rogersbdb03912011-09-14 00:55:44 -0700384 PushList(push_list);
385
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700386 // Increase frame to required size.
Ian Rogers790a6b72014-04-01 10:36:00 -0700387 CHECK_GT(frame_size, pushed_values * kFramePointerSize); // Must at least have space for Method*.
388 size_t adjust = frame_size - (pushed_values * kFramePointerSize);
Ian Rogersbdb03912011-09-14 00:55:44 -0700389 IncreaseFrameSize(adjust);
390
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700391 // Write out Method*.
Ian Rogersbdb03912011-09-14 00:55:44 -0700392 StoreToOffset(kStoreWord, R0, SP, 0);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700393
394 // Write out entry spills.
395 for (size_t i = 0; i < entry_spills.size(); ++i) {
396 Register reg = entry_spills.at(i).AsArm().AsCoreRegister();
Ian Rogers790a6b72014-04-01 10:36:00 -0700397 StoreToOffset(kStoreWord, reg, SP, frame_size + kFramePointerSize + (i * kFramePointerSize));
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700398 }
Ian Rogersb033c752011-07-20 12:22:35 -0700399}
400
Ian Rogers2c8f6532011-09-02 17:16:34 -0700401void ArmAssembler::RemoveFrame(size_t frame_size,
Ian Rogersbdb03912011-09-14 00:55:44 -0700402 const std::vector<ManagedRegister>& callee_save_regs) {
Elliott Hughes06b37d92011-10-16 11:51:29 -0700403 CHECK_ALIGNED(frame_size, kStackAlignment);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700404 // Compute callee saves to pop and PC.
Ian Rogersbdb03912011-09-14 00:55:44 -0700405 RegList pop_list = 1 << PC;
406 size_t pop_values = 1;
407 for (size_t i = 0; i < callee_save_regs.size(); i++) {
408 Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister();
409 pop_list |= 1 << reg;
410 pop_values++;
Ian Rogers0d666d82011-08-14 16:03:46 -0700411 }
Ian Rogersbdb03912011-09-14 00:55:44 -0700412
Dave Allison65fcc2c2014-04-28 13:45:27 -0700413 // Decrease frame to start of callee saves.
Ian Rogers790a6b72014-04-01 10:36:00 -0700414 CHECK_GT(frame_size, pop_values * kFramePointerSize);
415 size_t adjust = frame_size - (pop_values * kFramePointerSize);
Ian Rogersbdb03912011-09-14 00:55:44 -0700416 DecreaseFrameSize(adjust);
417
Dave Allison65fcc2c2014-04-28 13:45:27 -0700418 // Pop callee saves and PC.
Ian Rogersbdb03912011-09-14 00:55:44 -0700419 PopList(pop_list);
Ian Rogers0d666d82011-08-14 16:03:46 -0700420}
421
Ian Rogers2c8f6532011-09-02 17:16:34 -0700422void ArmAssembler::IncreaseFrameSize(size_t adjust) {
Ian Rogersb033c752011-07-20 12:22:35 -0700423 AddConstant(SP, -adjust);
424}
425
Ian Rogers2c8f6532011-09-02 17:16:34 -0700426void ArmAssembler::DecreaseFrameSize(size_t adjust) {
Ian Rogersb033c752011-07-20 12:22:35 -0700427 AddConstant(SP, adjust);
428}
429
Ian Rogers2c8f6532011-09-02 17:16:34 -0700430void ArmAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) {
431 ArmManagedRegister src = msrc.AsArm();
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700432 if (src.IsNoRegister()) {
433 CHECK_EQ(0u, size);
434 } else if (src.IsCoreRegister()) {
Ian Rogersb033c752011-07-20 12:22:35 -0700435 CHECK_EQ(4u, size);
436 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700437 } else if (src.IsRegisterPair()) {
438 CHECK_EQ(8u, size);
439 StoreToOffset(kStoreWord, src.AsRegisterPairLow(), SP, dest.Int32Value());
440 StoreToOffset(kStoreWord, src.AsRegisterPairHigh(),
441 SP, dest.Int32Value() + 4);
442 } else if (src.IsSRegister()) {
443 StoreSToOffset(src.AsSRegister(), SP, dest.Int32Value());
Ian Rogersb033c752011-07-20 12:22:35 -0700444 } else {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700445 CHECK(src.IsDRegister()) << src;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700446 StoreDToOffset(src.AsDRegister(), SP, dest.Int32Value());
Ian Rogersb033c752011-07-20 12:22:35 -0700447 }
448}
449
Ian Rogers2c8f6532011-09-02 17:16:34 -0700450void ArmAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
451 ArmManagedRegister src = msrc.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700452 CHECK(src.IsCoreRegister()) << src;
Ian Rogersb033c752011-07-20 12:22:35 -0700453 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
454}
455
Ian Rogers2c8f6532011-09-02 17:16:34 -0700456void ArmAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
457 ArmManagedRegister src = msrc.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700458 CHECK(src.IsCoreRegister()) << src;
Ian Rogersdf20fe02011-07-20 20:34:16 -0700459 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
460}
461
Ian Rogers2c8f6532011-09-02 17:16:34 -0700462void ArmAssembler::StoreSpanning(FrameOffset dest, ManagedRegister msrc,
463 FrameOffset in_off, ManagedRegister mscratch) {
464 ArmManagedRegister src = msrc.AsArm();
465 ArmManagedRegister scratch = mscratch.AsArm();
Ian Rogers7a99c112011-09-07 12:48:27 -0700466 StoreToOffset(kStoreWord, src.AsCoreRegister(), SP, dest.Int32Value());
467 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, in_off.Int32Value());
468 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
469}
470
Ian Rogers2c8f6532011-09-02 17:16:34 -0700471void ArmAssembler::CopyRef(FrameOffset dest, FrameOffset src,
472 ManagedRegister mscratch) {
473 ArmManagedRegister scratch = mscratch.AsArm();
Ian Rogersb033c752011-07-20 12:22:35 -0700474 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
475 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
476}
477
Ian Rogers2c8f6532011-09-02 17:16:34 -0700478void ArmAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base,
479 MemberOffset offs) {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700480 ArmManagedRegister dst = mdest.AsArm();
481 CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
482 LoadFromOffset(kLoadWord, dst.AsCoreRegister(),
Ian Rogers2c8f6532011-09-02 17:16:34 -0700483 base.AsArm().AsCoreRegister(), offs.Int32Value());
Hiroshi Yamauchie63a7452014-02-27 14:44:36 -0800484 if (kPoisonHeapReferences) {
485 rsb(dst.AsCoreRegister(), dst.AsCoreRegister(), ShifterOperand(0));
486 }
Ian Rogersb033c752011-07-20 12:22:35 -0700487}
488
Ian Rogers2c8f6532011-09-02 17:16:34 -0700489void ArmAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700490 ArmManagedRegister dst = mdest.AsArm();
491 CHECK(dst.IsCoreRegister()) << dst;
492 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), SP, src.Int32Value());
Elliott Hughes362f9bc2011-10-17 18:56:41 -0700493}
Ian Rogers2c8f6532011-09-02 17:16:34 -0700494
495void ArmAssembler::LoadRawPtr(ManagedRegister mdest, ManagedRegister base,
Ian Rogersa04d3972011-08-17 11:33:44 -0700496 Offset offs) {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700497 ArmManagedRegister dst = mdest.AsArm();
498 CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
499 LoadFromOffset(kLoadWord, dst.AsCoreRegister(),
Ian Rogers2c8f6532011-09-02 17:16:34 -0700500 base.AsArm().AsCoreRegister(), offs.Int32Value());
Ian Rogersa04d3972011-08-17 11:33:44 -0700501}
502
Ian Rogers2c8f6532011-09-02 17:16:34 -0700503void ArmAssembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
504 ManagedRegister mscratch) {
505 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700506 CHECK(scratch.IsCoreRegister()) << scratch;
Ian Rogersb033c752011-07-20 12:22:35 -0700507 LoadImmediate(scratch.AsCoreRegister(), imm);
508 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
509}
510
Ian Rogersdd7624d2014-03-14 17:43:00 -0700511void ArmAssembler::StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700512 ManagedRegister mscratch) {
513 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700514 CHECK(scratch.IsCoreRegister()) << scratch;
Ian Rogersb033c752011-07-20 12:22:35 -0700515 LoadImmediate(scratch.AsCoreRegister(), imm);
516 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), TR, dest.Int32Value());
517}
518
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700519static void EmitLoad(ArmAssembler* assembler, ManagedRegister m_dst,
520 Register src_register, int32_t src_offset, size_t size) {
521 ArmManagedRegister dst = m_dst.AsArm();
522 if (dst.IsNoRegister()) {
523 CHECK_EQ(0u, size) << dst;
524 } else if (dst.IsCoreRegister()) {
525 CHECK_EQ(4u, size) << dst;
526 assembler->LoadFromOffset(kLoadWord, dst.AsCoreRegister(), src_register, src_offset);
527 } else if (dst.IsRegisterPair()) {
528 CHECK_EQ(8u, size) << dst;
529 assembler->LoadFromOffset(kLoadWord, dst.AsRegisterPairLow(), src_register, src_offset);
530 assembler->LoadFromOffset(kLoadWord, dst.AsRegisterPairHigh(), src_register, src_offset + 4);
531 } else if (dst.IsSRegister()) {
532 assembler->LoadSFromOffset(dst.AsSRegister(), src_register, src_offset);
Ian Rogersb033c752011-07-20 12:22:35 -0700533 } else {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700534 CHECK(dst.IsDRegister()) << dst;
535 assembler->LoadDFromOffset(dst.AsDRegister(), src_register, src_offset);
Ian Rogersb033c752011-07-20 12:22:35 -0700536 }
537}
538
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700539void ArmAssembler::Load(ManagedRegister m_dst, FrameOffset src, size_t size) {
540 return EmitLoad(this, m_dst, SP, src.Int32Value(), size);
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700541}
542
Ian Rogersdd7624d2014-03-14 17:43:00 -0700543void ArmAssembler::LoadFromThread32(ManagedRegister m_dst, ThreadOffset<4> src, size_t size) {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700544 return EmitLoad(this, m_dst, TR, src.Int32Value(), size);
545}
546
Ian Rogersdd7624d2014-03-14 17:43:00 -0700547void ArmAssembler::LoadRawPtrFromThread32(ManagedRegister m_dst, ThreadOffset<4> offs) {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700548 ArmManagedRegister dst = m_dst.AsArm();
549 CHECK(dst.IsCoreRegister()) << dst;
550 LoadFromOffset(kLoadWord, dst.AsCoreRegister(), TR, offs.Int32Value());
Ian Rogersb033c752011-07-20 12:22:35 -0700551}
552
Ian Rogersdd7624d2014-03-14 17:43:00 -0700553void ArmAssembler::CopyRawPtrFromThread32(FrameOffset fr_offs,
554 ThreadOffset<4> thr_offs,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700555 ManagedRegister mscratch) {
556 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700557 CHECK(scratch.IsCoreRegister()) << scratch;
Ian Rogersb033c752011-07-20 12:22:35 -0700558 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
559 TR, thr_offs.Int32Value());
560 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
561 SP, fr_offs.Int32Value());
562}
563
Ian Rogersdd7624d2014-03-14 17:43:00 -0700564void ArmAssembler::CopyRawPtrToThread32(ThreadOffset<4> thr_offs,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700565 FrameOffset fr_offs,
566 ManagedRegister mscratch) {
567 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700568 CHECK(scratch.IsCoreRegister()) << scratch;
Ian Rogersb033c752011-07-20 12:22:35 -0700569 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
570 SP, fr_offs.Int32Value());
571 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
572 TR, thr_offs.Int32Value());
573}
574
Ian Rogersdd7624d2014-03-14 17:43:00 -0700575void ArmAssembler::StoreStackOffsetToThread32(ThreadOffset<4> thr_offs,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700576 FrameOffset fr_offs,
577 ManagedRegister mscratch) {
578 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700579 CHECK(scratch.IsCoreRegister()) << scratch;
Ian Rogersb033c752011-07-20 12:22:35 -0700580 AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value(), AL);
581 StoreToOffset(kStoreWord, scratch.AsCoreRegister(),
582 TR, thr_offs.Int32Value());
583}
584
Ian Rogersdd7624d2014-03-14 17:43:00 -0700585void ArmAssembler::StoreStackPointerToThread32(ThreadOffset<4> thr_offs) {
Ian Rogers45a76cb2011-07-21 22:00:15 -0700586 StoreToOffset(kStoreWord, SP, TR, thr_offs.Int32Value());
587}
588
jeffhao58136ca2012-05-24 13:40:11 -0700589void ArmAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
590 UNIMPLEMENTED(FATAL) << "no sign extension necessary for arm";
591}
592
jeffhaocee4d0c2012-06-15 14:42:01 -0700593void ArmAssembler::ZeroExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
594 UNIMPLEMENTED(FATAL) << "no zero extension necessary for arm";
595}
596
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700597void ArmAssembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t /*size*/) {
598 ArmManagedRegister dst = m_dst.AsArm();
599 ArmManagedRegister src = m_src.AsArm();
600 if (!dst.Equals(src)) {
601 if (dst.IsCoreRegister()) {
602 CHECK(src.IsCoreRegister()) << src;
603 mov(dst.AsCoreRegister(), ShifterOperand(src.AsCoreRegister()));
604 } else if (dst.IsDRegister()) {
605 CHECK(src.IsDRegister()) << src;
606 vmovd(dst.AsDRegister(), src.AsDRegister());
607 } else if (dst.IsSRegister()) {
608 CHECK(src.IsSRegister()) << src;
609 vmovs(dst.AsSRegister(), src.AsSRegister());
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700610 } else {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700611 CHECK(dst.IsRegisterPair()) << dst;
612 CHECK(src.IsRegisterPair()) << src;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700613 // Ensure that the first move doesn't clobber the input of the second.
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700614 if (src.AsRegisterPairHigh() != dst.AsRegisterPairLow()) {
615 mov(dst.AsRegisterPairLow(), ShifterOperand(src.AsRegisterPairLow()));
616 mov(dst.AsRegisterPairHigh(), ShifterOperand(src.AsRegisterPairHigh()));
Ian Rogers7a99c112011-09-07 12:48:27 -0700617 } else {
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700618 mov(dst.AsRegisterPairHigh(), ShifterOperand(src.AsRegisterPairHigh()));
619 mov(dst.AsRegisterPairLow(), ShifterOperand(src.AsRegisterPairLow()));
Ian Rogers7a99c112011-09-07 12:48:27 -0700620 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700621 }
Ian Rogersb033c752011-07-20 12:22:35 -0700622 }
623}
624
Ian Rogersdc51b792011-09-22 20:41:37 -0700625void ArmAssembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) {
Ian Rogers2c8f6532011-09-02 17:16:34 -0700626 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700627 CHECK(scratch.IsCoreRegister()) << scratch;
628 CHECK(size == 4 || size == 8) << size;
Ian Rogersb033c752011-07-20 12:22:35 -0700629 if (size == 4) {
Ian Rogersdc51b792011-09-22 20:41:37 -0700630 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
631 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700632 } else if (size == 8) {
Ian Rogersdc51b792011-09-22 20:41:37 -0700633 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value());
634 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value());
635 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP, src.Int32Value() + 4);
636 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, dest.Int32Value() + 4);
Ian Rogersb033c752011-07-20 12:22:35 -0700637 }
638}
639
Ian Rogersdc51b792011-09-22 20:41:37 -0700640void ArmAssembler::Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
641 ManagedRegister mscratch, size_t size) {
642 Register scratch = mscratch.AsArm().AsCoreRegister();
643 CHECK_EQ(size, 4u);
644 LoadFromOffset(kLoadWord, scratch, src_base.AsArm().AsCoreRegister(), src_offset.Int32Value());
645 StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
646}
647
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700648void ArmAssembler::Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
649 ManagedRegister mscratch, size_t size) {
650 Register scratch = mscratch.AsArm().AsCoreRegister();
651 CHECK_EQ(size, 4u);
652 LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
653 StoreToOffset(kStoreWord, scratch, dest_base.AsArm().AsCoreRegister(), dest_offset.Int32Value());
654}
655
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700656void ArmAssembler::Copy(FrameOffset /*dst*/, FrameOffset /*src_base*/, Offset /*src_offset*/,
657 ManagedRegister /*mscratch*/, size_t /*size*/) {
Ian Rogersdc51b792011-09-22 20:41:37 -0700658 UNIMPLEMENTED(FATAL);
659}
660
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700661void ArmAssembler::Copy(ManagedRegister dest, Offset dest_offset,
662 ManagedRegister src, Offset src_offset,
663 ManagedRegister mscratch, size_t size) {
Ian Rogersdc51b792011-09-22 20:41:37 -0700664 CHECK_EQ(size, 4u);
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700665 Register scratch = mscratch.AsArm().AsCoreRegister();
666 LoadFromOffset(kLoadWord, scratch, src.AsArm().AsCoreRegister(), src_offset.Int32Value());
667 StoreToOffset(kStoreWord, scratch, dest.AsArm().AsCoreRegister(), dest_offset.Int32Value());
668}
669
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700670void ArmAssembler::Copy(FrameOffset /*dst*/, Offset /*dest_offset*/, FrameOffset /*src*/, Offset /*src_offset*/,
671 ManagedRegister /*scratch*/, size_t /*size*/) {
Ian Rogers5a7a74a2011-09-26 16:32:29 -0700672 UNIMPLEMENTED(FATAL);
Ian Rogersdc51b792011-09-22 20:41:37 -0700673}
674
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700675void ArmAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
676 FrameOffset handle_scope_offset,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700677 ManagedRegister min_reg, bool null_allowed) {
678 ArmManagedRegister out_reg = mout_reg.AsArm();
679 ArmManagedRegister in_reg = min_reg.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700680 CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
681 CHECK(out_reg.IsCoreRegister()) << out_reg;
Ian Rogersb033c752011-07-20 12:22:35 -0700682 if (null_allowed) {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700683 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
684 // the address in the handle scope holding the reference.
Ian Rogersb033c752011-07-20 12:22:35 -0700685 // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700686 if (in_reg.IsNoRegister()) {
687 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700688 SP, handle_scope_offset.Int32Value());
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700689 in_reg = out_reg;
690 }
Ian Rogersb033c752011-07-20 12:22:35 -0700691 cmp(in_reg.AsCoreRegister(), ShifterOperand(0));
692 if (!out_reg.Equals(in_reg)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700693 it(EQ, kItElse);
Ian Rogersb033c752011-07-20 12:22:35 -0700694 LoadImmediate(out_reg.AsCoreRegister(), 0, EQ);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700695 } else {
696 it(NE);
Ian Rogersb033c752011-07-20 12:22:35 -0700697 }
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700698 AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE);
Ian Rogersb033c752011-07-20 12:22:35 -0700699 } else {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700700 AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL);
Ian Rogersb033c752011-07-20 12:22:35 -0700701 }
702}
703
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700704void ArmAssembler::CreateHandleScopeEntry(FrameOffset out_off,
705 FrameOffset handle_scope_offset,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700706 ManagedRegister mscratch,
707 bool null_allowed) {
708 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700709 CHECK(scratch.IsCoreRegister()) << scratch;
Ian Rogersb033c752011-07-20 12:22:35 -0700710 if (null_allowed) {
711 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(), SP,
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700712 handle_scope_offset.Int32Value());
713 // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
714 // the address in the handle scope holding the reference.
715 // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
Ian Rogersb033c752011-07-20 12:22:35 -0700716 cmp(scratch.AsCoreRegister(), ShifterOperand(0));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700717 it(NE);
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700718 AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), NE);
Ian Rogersb033c752011-07-20 12:22:35 -0700719 } else {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700720 AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), AL);
Ian Rogersb033c752011-07-20 12:22:35 -0700721 }
722 StoreToOffset(kStoreWord, scratch.AsCoreRegister(), SP, out_off.Int32Value());
723}
724
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700725void ArmAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
Ian Rogers2c8f6532011-09-02 17:16:34 -0700726 ManagedRegister min_reg) {
727 ArmManagedRegister out_reg = mout_reg.AsArm();
728 ArmManagedRegister in_reg = min_reg.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700729 CHECK(out_reg.IsCoreRegister()) << out_reg;
730 CHECK(in_reg.IsCoreRegister()) << in_reg;
Ian Rogersb033c752011-07-20 12:22:35 -0700731 Label null_arg;
732 if (!out_reg.Equals(in_reg)) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700733 LoadImmediate(out_reg.AsCoreRegister(), 0, EQ); // TODO: why EQ?
Ian Rogersb033c752011-07-20 12:22:35 -0700734 }
735 cmp(in_reg.AsCoreRegister(), ShifterOperand(0));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700736 it(NE);
Ian Rogersdf20fe02011-07-20 20:34:16 -0700737 LoadFromOffset(kLoadWord, out_reg.AsCoreRegister(),
738 in_reg.AsCoreRegister(), 0, NE);
Ian Rogersb033c752011-07-20 12:22:35 -0700739}
740
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700741void ArmAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700742 // TODO: not validating references.
Ian Rogersb033c752011-07-20 12:22:35 -0700743}
744
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700745void ArmAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
Dave Allison65fcc2c2014-04-28 13:45:27 -0700746 // TODO: not validating references.
Ian Rogersb033c752011-07-20 12:22:35 -0700747}
748
Ian Rogers2c8f6532011-09-02 17:16:34 -0700749void ArmAssembler::Call(ManagedRegister mbase, Offset offset,
750 ManagedRegister mscratch) {
751 ArmManagedRegister base = mbase.AsArm();
752 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700753 CHECK(base.IsCoreRegister()) << base;
754 CHECK(scratch.IsCoreRegister()) << scratch;
Ian Rogersb033c752011-07-20 12:22:35 -0700755 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
756 base.AsCoreRegister(), offset.Int32Value());
757 blx(scratch.AsCoreRegister());
Dave Allison65fcc2c2014-04-28 13:45:27 -0700758 // TODO: place reference map on call.
Ian Rogersb033c752011-07-20 12:22:35 -0700759}
760
Ian Rogers2c8f6532011-09-02 17:16:34 -0700761void ArmAssembler::Call(FrameOffset base, Offset offset,
762 ManagedRegister mscratch) {
763 ArmManagedRegister scratch = mscratch.AsArm();
Elliott Hughesbf2739d2012-05-21 14:30:16 -0700764 CHECK(scratch.IsCoreRegister()) << scratch;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700765 // Call *(*(SP + base) + offset)
766 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
767 SP, base.Int32Value());
768 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
769 scratch.AsCoreRegister(), offset.Int32Value());
770 blx(scratch.AsCoreRegister());
771 // TODO: place reference map on call
772}
773
Ian Rogersdd7624d2014-03-14 17:43:00 -0700774void ArmAssembler::CallFromThread32(ThreadOffset<4> /*offset*/, ManagedRegister /*scratch*/) {
Ian Rogersbdb03912011-09-14 00:55:44 -0700775 UNIMPLEMENTED(FATAL);
776}
777
Ian Rogers2c8f6532011-09-02 17:16:34 -0700778void ArmAssembler::GetCurrentThread(ManagedRegister tr) {
779 mov(tr.AsArm().AsCoreRegister(), ShifterOperand(TR));
Shih-wei Liao668512a2011-09-01 14:18:34 -0700780}
781
Ian Rogers2c8f6532011-09-02 17:16:34 -0700782void ArmAssembler::GetCurrentThread(FrameOffset offset,
Elliott Hughes1bac54f2012-03-16 12:48:31 -0700783 ManagedRegister /*scratch*/) {
Shih-wei Liao668512a2011-09-01 14:18:34 -0700784 StoreToOffset(kStoreWord, TR, SP, offset.Int32Value(), AL);
785}
786
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700787void ArmAssembler::ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) {
Ian Rogers2c8f6532011-09-02 17:16:34 -0700788 ArmManagedRegister scratch = mscratch.AsArm();
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700789 ArmExceptionSlowPath* slow = new ArmExceptionSlowPath(scratch, stack_adjust);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700790 buffer_.EnqueueSlowPath(slow);
791 LoadFromOffset(kLoadWord, scratch.AsCoreRegister(),
Ian Rogersdd7624d2014-03-14 17:43:00 -0700792 TR, Thread::ExceptionOffset<4>().Int32Value());
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700793 cmp(scratch.AsCoreRegister(), ShifterOperand(0));
794 b(slow->Entry(), NE);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700795}
796
Ian Rogers2c8f6532011-09-02 17:16:34 -0700797void ArmExceptionSlowPath::Emit(Assembler* sasm) {
798 ArmAssembler* sp_asm = down_cast<ArmAssembler*>(sasm);
799#define __ sp_asm->
800 __ Bind(&entry_);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700801 if (stack_adjust_ != 0) { // Fix up the frame.
802 __ DecreaseFrameSize(stack_adjust_);
803 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700804 // Pass exception object as argument.
805 // Don't care about preserving R0 as this call won't return.
Ian Rogers67375ac2011-09-14 00:55:44 -0700806 __ mov(R0, ShifterOperand(scratch_.AsCoreRegister()));
Dave Allison65fcc2c2014-04-28 13:45:27 -0700807 // Set up call to Thread::Current()->pDeliverException.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700808 __ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value());
Ian Rogers2c8f6532011-09-02 17:16:34 -0700809 __ blx(R12);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700810 // Call never returns.
Ian Rogers67375ac2011-09-14 00:55:44 -0700811 __ bkpt(0);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700812#undef __
Ian Rogers45a76cb2011-07-21 22:00:15 -0700813}
814
Dave Allison65fcc2c2014-04-28 13:45:27 -0700815
816static int LeadingZeros(uint32_t val) {
817 uint32_t alt;
818 int32_t n;
819 int32_t count;
820
821 count = 16;
822 n = 32;
823 do {
824 alt = val >> count;
825 if (alt != 0) {
826 n = n - count;
827 val = alt;
828 }
829 count >>= 1;
830 } while (count);
831 return n - val;
832}
833
834
835uint32_t ArmAssembler::ModifiedImmediate(uint32_t value) {
836 int32_t z_leading;
837 int32_t z_trailing;
838 uint32_t b0 = value & 0xff;
839
840 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
841 if (value <= 0xFF)
842 return b0; // 0:000:a:bcdefgh.
843 if (value == ((b0 << 16) | b0))
844 return (0x1 << 12) | b0; /* 0:001:a:bcdefgh */
845 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
846 return (0x3 << 12) | b0; /* 0:011:a:bcdefgh */
847 b0 = (value >> 8) & 0xff;
848 if (value == ((b0 << 24) | (b0 << 8)))
849 return (0x2 << 12) | b0; /* 0:010:a:bcdefgh */
850 /* Can we do it with rotation? */
851 z_leading = LeadingZeros(value);
852 z_trailing = 32 - LeadingZeros(~value & (value - 1));
853 /* A run of eight or fewer active bits? */
854 if ((z_leading + z_trailing) < 24)
855 return kInvalidModifiedImmediate; /* No - bail */
856 /* left-justify the constant, discarding msb (known to be 1) */
857 value <<= z_leading + 1;
858 /* Create bcdefgh */
859 value >>= 25;
860
861 /* Put it all together */
862 uint32_t v = 8 + z_leading;
863
864 uint32_t i = (v & 0b10000) >> 4;
865 uint32_t imm3 = (v >> 1) & 0b111;
866 uint32_t a = v & 1;
867 return value | i << 26 | imm3 << 12 | a << 7;
868}
869
Ian Rogers2c8f6532011-09-02 17:16:34 -0700870} // namespace arm
Carl Shapiro6b6b5f02011-06-21 15:05:09 -0700871} // namespace art