Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
3
* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "jit/arm/MacroAssembler-arm.h"
8
9
#include "mozilla/Attributes.h"
10
#include "mozilla/Casting.h"
11
#include "mozilla/DebugOnly.h"
12
#include "mozilla/MathAlgorithms.h"
13
#include "mozilla/Maybe.h"
14
15
#include "jit/arm/Simulator-arm.h"
16
#include "jit/AtomicOp.h"
17
#include "jit/AtomicOperations.h"
18
#include "jit/Bailouts.h"
19
#include "jit/BaselineFrame.h"
20
#include "jit/JitFrames.h"
21
#include "jit/MacroAssembler.h"
22
#include "jit/MoveEmitter.h"
23
#include "util/Memory.h"
24
#include "vm/JitActivation.h" // js::jit::JitActivation
25
26
#include "jit/MacroAssembler-inl.h"
27
28
using namespace js;
29
using namespace jit;
30
31
using mozilla::Abs;
32
using mozilla::BitwiseCast;
33
using mozilla::DebugOnly;
34
using mozilla::IsPositiveZero;
35
using mozilla::Maybe;
36
37
bool isValueDTRDCandidate(ValueOperand& val) {
38
// In order to be used for a DTRD memory function, the two target registers
39
// need to be a) Adjacent, with the tag larger than the payload, and b)
40
// Aligned to a multiple of two.
41
if ((val.typeReg().code() != (val.payloadReg().code() + 1))) {
42
return false;
43
}
44
if ((val.payloadReg().code() & 1) != 0) {
45
return false;
46
}
47
return true;
48
}
49
50
void MacroAssemblerARM::convertBoolToInt32(Register source, Register dest) {
51
// Note that C++ bool is only 1 byte, so zero extend it to clear the
52
// higher-order bits.
53
as_and(dest, source, Imm8(0xff));
54
}
55
56
void MacroAssemblerARM::convertInt32ToDouble(Register src,
57
FloatRegister dest_) {
58
// Direct conversions aren't possible.
59
VFPRegister dest = VFPRegister(dest_);
60
as_vxfer(src, InvalidReg, dest.sintOverlay(), CoreToFloat);
61
as_vcvt(dest, dest.sintOverlay());
62
}
63
64
void MacroAssemblerARM::convertInt32ToDouble(const Address& src,
65
FloatRegister dest) {
66
ScratchDoubleScope scratch(asMasm());
67
SecondScratchRegisterScope scratch2(asMasm());
68
ma_vldr(src, scratch, scratch2);
69
as_vcvt(dest, VFPRegister(scratch).sintOverlay());
70
}
71
72
void MacroAssemblerARM::convertInt32ToDouble(const BaseIndex& src,
73
FloatRegister dest) {
74
Register base = src.base;
75
uint32_t scale = Imm32::ShiftOf(src.scale).value;
76
77
ScratchRegisterScope scratch(asMasm());
78
SecondScratchRegisterScope scratch2(asMasm());
79
80
if (src.offset != 0) {
81
ma_add(base, Imm32(src.offset), scratch, scratch2);
82
base = scratch;
83
}
84
ma_ldr(DTRAddr(base, DtrRegImmShift(src.index, LSL, scale)), scratch);
85
convertInt32ToDouble(scratch, dest);
86
}
87
88
void MacroAssemblerARM::convertUInt32ToDouble(Register src,
89
FloatRegister dest_) {
90
// Direct conversions aren't possible.
91
VFPRegister dest = VFPRegister(dest_);
92
as_vxfer(src, InvalidReg, dest.uintOverlay(), CoreToFloat);
93
as_vcvt(dest, dest.uintOverlay());
94
}
95
96
static const double TO_DOUBLE_HIGH_SCALE = 0x100000000;
97
98
void MacroAssemblerARM::convertUInt32ToFloat32(Register src,
99
FloatRegister dest_) {
100
// Direct conversions aren't possible.
101
VFPRegister dest = VFPRegister(dest_);
102
as_vxfer(src, InvalidReg, dest.uintOverlay(), CoreToFloat);
103
as_vcvt(VFPRegister(dest).singleOverlay(), dest.uintOverlay());
104
}
105
106
void MacroAssemblerARM::convertDoubleToFloat32(FloatRegister src,
107
FloatRegister dest,
108
Condition c) {
109
as_vcvt(VFPRegister(dest).singleOverlay(), VFPRegister(src), false, c);
110
}
111
112
// Checks whether a double is representable as a 32-bit integer. If so, the
113
// integer is written to the output register. Otherwise, a bailout is taken to
114
// the given snapshot. This function overwrites the scratch float register.
115
void MacroAssemblerARM::convertDoubleToInt32(FloatRegister src, Register dest,
116
Label* fail,
117
bool negativeZeroCheck) {
118
// Convert the floating point value to an integer, if it did not fit, then
119
// when we convert it *back* to a float, it will have a different value,
120
// which we can test.
121
ScratchDoubleScope scratchDouble(asMasm());
122
ScratchRegisterScope scratch(asMasm());
123
124
FloatRegister scratchSIntReg = scratchDouble.sintOverlay();
125
126
ma_vcvt_F64_I32(src, scratchSIntReg);
127
// Move the value into the dest register.
128
ma_vxfer(scratchSIntReg, dest);
129
ma_vcvt_I32_F64(scratchSIntReg, scratchDouble);
130
ma_vcmp(src, scratchDouble);
131
as_vmrs(pc);
132
ma_b(fail, Assembler::VFP_NotEqualOrUnordered);
133
134
if (negativeZeroCheck) {
135
as_cmp(dest, Imm8(0));
136
// Test and bail for -0.0, when integer result is 0. Move the top word
137
// of the double into the output reg, if it is non-zero, then the
138
// original value was -0.0.
139
as_vxfer(dest, InvalidReg, src, FloatToCore, Assembler::Equal, 1);
140
ma_cmp(dest, Imm32(0x80000000), scratch, Assembler::Equal);
141
ma_b(fail, Assembler::Equal);
142
}
143
}
144
145
// Checks whether a float32 is representable as a 32-bit integer. If so, the
146
// integer is written to the output register. Otherwise, a bailout is taken to
147
// the given snapshot. This function overwrites the scratch float register.
148
void MacroAssemblerARM::convertFloat32ToInt32(FloatRegister src, Register dest,
149
Label* fail,
150
bool negativeZeroCheck) {
151
// Converting the floating point value to an integer and then converting it
152
// back to a float32 would not work, as float to int32 conversions are
153
// clamping (e.g. float(INT32_MAX + 1) would get converted into INT32_MAX
154
// and then back to float(INT32_MAX + 1)). If this ever happens, we just
155
// bail out.
156
ScratchFloat32Scope scratchFloat(asMasm());
157
ScratchRegisterScope scratch(asMasm());
158
159
FloatRegister ScratchSIntReg = scratchFloat.sintOverlay();
160
ma_vcvt_F32_I32(src, ScratchSIntReg);
161
162
// Store the result
163
ma_vxfer(ScratchSIntReg, dest);
164
165
ma_vcvt_I32_F32(ScratchSIntReg, scratchFloat);
166
ma_vcmp(src, scratchFloat);
167
as_vmrs(pc);
168
ma_b(fail, Assembler::VFP_NotEqualOrUnordered);
169
170
// Bail out in the clamped cases.
171
ma_cmp(dest, Imm32(0x7fffffff), scratch);
172
ma_cmp(dest, Imm32(0x80000000), scratch, Assembler::NotEqual);
173
ma_b(fail, Assembler::Equal);
174
175
if (negativeZeroCheck) {
176
as_cmp(dest, Imm8(0));
177
// Test and bail for -0.0, when integer result is 0. Move the float into
178
// the output reg, and if it is non-zero then the original value was
179
// -0.0
180
as_vxfer(dest, InvalidReg, VFPRegister(src).singleOverlay(), FloatToCore,
181
Assembler::Equal, 0);
182
ma_cmp(dest, Imm32(0x80000000), scratch, Assembler::Equal);
183
ma_b(fail, Assembler::Equal);
184
}
185
}
186
187
void MacroAssemblerARM::convertFloat32ToDouble(FloatRegister src,
188
FloatRegister dest) {
189
MOZ_ASSERT(dest.isDouble());
190
MOZ_ASSERT(src.isSingle());
191
as_vcvt(VFPRegister(dest), VFPRegister(src).singleOverlay());
192
}
193
194
void MacroAssemblerARM::convertInt32ToFloat32(Register src,
195
FloatRegister dest) {
196
// Direct conversions aren't possible.
197
as_vxfer(src, InvalidReg, dest.sintOverlay(), CoreToFloat);
198
as_vcvt(dest.singleOverlay(), dest.sintOverlay());
199
}
200
201
void MacroAssemblerARM::convertInt32ToFloat32(const Address& src,
202
FloatRegister dest) {
203
ScratchFloat32Scope scratch(asMasm());
204
SecondScratchRegisterScope scratch2(asMasm());
205
ma_vldr(src, scratch, scratch2);
206
as_vcvt(dest, VFPRegister(scratch).sintOverlay());
207
}
208
209
bool MacroAssemblerARM::alu_dbl(Register src1, Imm32 imm, Register dest,
210
ALUOp op, SBit s, Condition c) {
211
if ((s == SetCC && !condsAreSafe(op)) || !can_dbl(op)) {
212
return false;
213
}
214
215
ALUOp interop = getDestVariant(op);
216
Imm8::TwoImm8mData both = Imm8::EncodeTwoImms(imm.value);
217
if (both.fst().invalid()) {
218
return false;
219
}
220
221
// For the most part, there is no good reason to set the condition codes for
222
// the first instruction. We can do better things if the second instruction
223
// doesn't have a dest, such as check for overflow by doing first operation
224
// don't do second operation if first operation overflowed. This preserves
225
// the overflow condition code. Unfortunately, it is horribly brittle.
226
as_alu(dest, src1, Operand2(both.fst()), interop, LeaveCC, c);
227
as_alu(dest, dest, Operand2(both.snd()), op, s, c);
228
return true;
229
}
230
231
void MacroAssemblerARM::ma_alu(Register src1, Imm32 imm, Register dest,
232
AutoRegisterScope& scratch, ALUOp op, SBit s,
233
Condition c) {
234
// ma_mov should be used for moves.
235
MOZ_ASSERT(op != OpMov);
236
MOZ_ASSERT(op != OpMvn);
237
MOZ_ASSERT(src1 != scratch);
238
239
// As it turns out, if you ask for a compare-like instruction you *probably*
240
// want it to set condition codes.
241
MOZ_ASSERT_IF(dest == InvalidReg, s == SetCC);
242
243
// The operator gives us the ability to determine how this can be used.
244
Imm8 imm8 = Imm8(imm.value);
245
// One instruction: If we can encode it using an imm8m, then do so.
246
if (!imm8.invalid()) {
247
as_alu(dest, src1, imm8, op, s, c);
248
return;
249
}
250
251
// One instruction, negated:
252
Imm32 negImm = imm;
253
Register negDest;
254
ALUOp negOp = ALUNeg(op, dest, scratch, &negImm, &negDest);
255
Imm8 negImm8 = Imm8(negImm.value);
256
// 'add r1, r2, -15' can be replaced with 'sub r1, r2, 15'.
257
// The dest can be replaced (InvalidReg => scratch).
258
// This is useful if we wish to negate tst. tst has an invalid (aka not
259
// used) dest, but its negation bic requires a dest.
260
if (negOp != OpInvalid && !negImm8.invalid()) {
261
as_alu(negDest, src1, negImm8, negOp, s, c);
262
return;
263
}
264
265
// Start by attempting to generate a two instruction form. Some things
266
// cannot be made into two-inst forms correctly. Namely, adds dest, src,
267
// 0xffff. Since we want the condition codes (and don't know which ones
268
// will be checked), we need to assume that the overflow flag will be
269
// checked and add{,s} dest, src, 0xff00; add{,s} dest, dest, 0xff is not
270
// guaranteed to set the overflof flag the same as the (theoretical) one
271
// instruction variant.
272
if (alu_dbl(src1, imm, dest, op, s, c)) {
273
return;
274
}
275
276
// And try with its negative.
277
if (negOp != OpInvalid && alu_dbl(src1, negImm, negDest, negOp, s, c)) {
278
return;
279
}
280
281
ma_mov(imm, scratch, c);
282
as_alu(dest, src1, O2Reg(scratch), op, s, c);
283
}
284
285
void MacroAssemblerARM::ma_alu(Register src1, Operand op2, Register dest,
286
ALUOp op, SBit s, Assembler::Condition c) {
287
MOZ_ASSERT(op2.tag() == Operand::Tag::OP2);
288
as_alu(dest, src1, op2.toOp2(), op, s, c);
289
}
290
291
void MacroAssemblerARM::ma_alu(Register src1, Operand2 op2, Register dest,
292
ALUOp op, SBit s, Condition c) {
293
as_alu(dest, src1, op2, op, s, c);
294
}
295
296
void MacroAssemblerARM::ma_nop() { as_nop(); }
297
298
BufferOffset MacroAssemblerARM::ma_movPatchable(Imm32 imm_, Register dest,
299
Assembler::Condition c) {
300
int32_t imm = imm_.value;
301
if (HasMOVWT()) {
302
BufferOffset offset = as_movw(dest, Imm16(imm & 0xffff), c);
303
as_movt(dest, Imm16(imm >> 16 & 0xffff), c);
304
return offset;
305
} else {
306
return as_Imm32Pool(dest, imm, c);
307
}
308
}
309
310
BufferOffset MacroAssemblerARM::ma_movPatchable(ImmPtr imm, Register dest,
311
Assembler::Condition c) {
312
return ma_movPatchable(Imm32(int32_t(imm.value)), dest, c);
313
}
314
315
/* static */
316
template <class Iter>
317
void MacroAssemblerARM::ma_mov_patch(Imm32 imm32, Register dest,
318
Assembler::Condition c, RelocStyle rs,
319
Iter iter) {
320
// The current instruction must be an actual instruction,
321
// not automatically-inserted boilerplate.
322
MOZ_ASSERT(iter.cur());
323
MOZ_ASSERT(iter.cur() == iter.maybeSkipAutomaticInstructions());
324
325
int32_t imm = imm32.value;
326
switch (rs) {
327
case L_MOVWT:
328
Assembler::as_movw_patch(dest, Imm16(imm & 0xffff), c, iter.cur());
329
Assembler::as_movt_patch(dest, Imm16(imm >> 16 & 0xffff), c, iter.next());
330
break;
331
case L_LDR:
332
Assembler::WritePoolEntry(iter.cur(), c, imm);
333
break;
334
}
335
}
336
337
template void MacroAssemblerARM::ma_mov_patch(Imm32 imm32, Register dest,
338
Assembler::Condition c,
339
RelocStyle rs,
340
InstructionIterator iter);
341
template void MacroAssemblerARM::ma_mov_patch(Imm32 imm32, Register dest,
342
Assembler::Condition c,
343
RelocStyle rs,
344
BufferInstructionIterator iter);
345
346
void MacroAssemblerARM::ma_mov(Register src, Register dest, SBit s,
347
Assembler::Condition c) {
348
if (s == SetCC || dest != src) {
349
as_mov(dest, O2Reg(src), s, c);
350
}
351
}
352
353
void MacroAssemblerARM::ma_mov(Imm32 imm, Register dest,
354
Assembler::Condition c) {
355
// Try mov with Imm8 operand.
356
Imm8 imm8 = Imm8(imm.value);
357
if (!imm8.invalid()) {
358
as_alu(dest, InvalidReg, imm8, OpMov, LeaveCC, c);
359
return;
360
}
361
362
// Try mvn with Imm8 operand.
363
Imm8 negImm8 = Imm8(~imm.value);
364
if (!negImm8.invalid()) {
365
as_alu(dest, InvalidReg, negImm8, OpMvn, LeaveCC, c);
366
return;
367
}
368
369
// Try movw/movt.
370
if (HasMOVWT()) {
371
// ARMv7 supports movw/movt. movw zero-extends its 16 bit argument,
372
// so we can set the register this way. movt leaves the bottom 16
373
// bits in tact, so we always need a movw.
374
as_movw(dest, Imm16(imm.value & 0xffff), c);
375
if (uint32_t(imm.value) >> 16) {
376
as_movt(dest, Imm16(uint32_t(imm.value) >> 16), c);
377
}
378
return;
379
}
380
381
// If we don't have movw/movt, we need a load.
382
as_Imm32Pool(dest, imm.value, c);
383
}
384
385
void MacroAssemblerARM::ma_mov(ImmWord imm, Register dest,
386
Assembler::Condition c) {
387
ma_mov(Imm32(imm.value), dest, c);
388
}
389
390
void MacroAssemblerARM::ma_mov(ImmGCPtr ptr, Register dest) {
391
BufferOffset offset =
392
ma_movPatchable(Imm32(uintptr_t(ptr.value)), dest, Always);
393
writeDataRelocation(offset, ptr);
394
}
395
396
// Shifts (just a move with a shifting op2)
397
void MacroAssemblerARM::ma_lsl(Imm32 shift, Register src, Register dst) {
398
as_mov(dst, lsl(src, shift.value));
399
}
400
401
void MacroAssemblerARM::ma_lsr(Imm32 shift, Register src, Register dst) {
402
as_mov(dst, lsr(src, shift.value));
403
}
404
405
void MacroAssemblerARM::ma_asr(Imm32 shift, Register src, Register dst) {
406
as_mov(dst, asr(src, shift.value));
407
}
408
409
void MacroAssemblerARM::ma_ror(Imm32 shift, Register src, Register dst) {
410
as_mov(dst, ror(src, shift.value));
411
}
412
413
void MacroAssemblerARM::ma_rol(Imm32 shift, Register src, Register dst) {
414
as_mov(dst, rol(src, shift.value));
415
}
416
417
// Shifts (just a move with a shifting op2)
418
void MacroAssemblerARM::ma_lsl(Register shift, Register src, Register dst) {
419
as_mov(dst, lsl(src, shift));
420
}
421
422
void MacroAssemblerARM::ma_lsr(Register shift, Register src, Register dst) {
423
as_mov(dst, lsr(src, shift));
424
}
425
426
void MacroAssemblerARM::ma_asr(Register shift, Register src, Register dst) {
427
as_mov(dst, asr(src, shift));
428
}
429
430
void MacroAssemblerARM::ma_ror(Register shift, Register src, Register dst) {
431
as_mov(dst, ror(src, shift));
432
}
433
434
void MacroAssemblerARM::ma_rol(Register shift, Register src, Register dst,
435
AutoRegisterScope& scratch) {
436
as_rsb(scratch, shift, Imm8(32));
437
as_mov(dst, ror(src, scratch));
438
}
439
440
// Move not (dest <- ~src)
441
void MacroAssemblerARM::ma_mvn(Register src1, Register dest, SBit s,
442
Assembler::Condition c) {
443
as_alu(dest, InvalidReg, O2Reg(src1), OpMvn, s, c);
444
}
445
446
// Negate (dest <- -src), src is a register, rather than a general op2.
447
void MacroAssemblerARM::ma_neg(Register src1, Register dest, SBit s,
448
Assembler::Condition c) {
449
as_rsb(dest, src1, Imm8(0), s, c);
450
}
451
452
// And.
453
void MacroAssemblerARM::ma_and(Register src, Register dest, SBit s,
454
Assembler::Condition c) {
455
ma_and(dest, src, dest);
456
}
457
458
void MacroAssemblerARM::ma_and(Register src1, Register src2, Register dest,
459
SBit s, Assembler::Condition c) {
460
as_and(dest, src1, O2Reg(src2), s, c);
461
}
462
463
void MacroAssemblerARM::ma_and(Imm32 imm, Register dest,
464
AutoRegisterScope& scratch, SBit s,
465
Assembler::Condition c) {
466
ma_alu(dest, imm, dest, scratch, OpAnd, s, c);
467
}
468
469
void MacroAssemblerARM::ma_and(Imm32 imm, Register src1, Register dest,
470
AutoRegisterScope& scratch, SBit s,
471
Assembler::Condition c) {
472
ma_alu(src1, imm, dest, scratch, OpAnd, s, c);
473
}
474
475
// Bit clear (dest <- dest & ~imm) or (dest <- src1 & ~src2).
476
void MacroAssemblerARM::ma_bic(Imm32 imm, Register dest,
477
AutoRegisterScope& scratch, SBit s,
478
Assembler::Condition c) {
479
ma_alu(dest, imm, dest, scratch, OpBic, s, c);
480
}
481
482
// Exclusive or.
483
void MacroAssemblerARM::ma_eor(Register src, Register dest, SBit s,
484
Assembler::Condition c) {
485
ma_eor(dest, src, dest, s, c);
486
}
487
488
void MacroAssemblerARM::ma_eor(Register src1, Register src2, Register dest,
489
SBit s, Assembler::Condition c) {
490
as_eor(dest, src1, O2Reg(src2), s, c);
491
}
492
493
void MacroAssemblerARM::ma_eor(Imm32 imm, Register dest,
494
AutoRegisterScope& scratch, SBit s,
495
Assembler::Condition c) {
496
ma_alu(dest, imm, dest, scratch, OpEor, s, c);
497
}
498
499
void MacroAssemblerARM::ma_eor(Imm32 imm, Register src1, Register dest,
500
AutoRegisterScope& scratch, SBit s,
501
Assembler::Condition c) {
502
ma_alu(src1, imm, dest, scratch, OpEor, s, c);
503
}
504
505
// Or.
506
void MacroAssemblerARM::ma_orr(Register src, Register dest, SBit s,
507
Assembler::Condition c) {
508
ma_orr(dest, src, dest, s, c);
509
}
510
511
void MacroAssemblerARM::ma_orr(Register src1, Register src2, Register dest,
512
SBit s, Assembler::Condition c) {
513
as_orr(dest, src1, O2Reg(src2), s, c);
514
}
515
516
void MacroAssemblerARM::ma_orr(Imm32 imm, Register dest,
517
AutoRegisterScope& scratch, SBit s,
518
Assembler::Condition c) {
519
ma_alu(dest, imm, dest, scratch, OpOrr, s, c);
520
}
521
522
void MacroAssemblerARM::ma_orr(Imm32 imm, Register src1, Register dest,
523
AutoRegisterScope& scratch, SBit s,
524
Assembler::Condition c) {
525
ma_alu(src1, imm, dest, scratch, OpOrr, s, c);
526
}
527
528
// Arithmetic-based ops.
529
// Add with carry.
530
void MacroAssemblerARM::ma_adc(Imm32 imm, Register dest,
531
AutoRegisterScope& scratch, SBit s,
532
Condition c) {
533
ma_alu(dest, imm, dest, scratch, OpAdc, s, c);
534
}
535
536
void MacroAssemblerARM::ma_adc(Register src, Register dest, SBit s,
537
Condition c) {
538
as_alu(dest, dest, O2Reg(src), OpAdc, s, c);
539
}
540
541
void MacroAssemblerARM::ma_adc(Register src1, Register src2, Register dest,
542
SBit s, Condition c) {
543
as_alu(dest, src1, O2Reg(src2), OpAdc, s, c);
544
}
545
546
// Add.
547
void MacroAssemblerARM::ma_add(Imm32 imm, Register dest,
548
AutoRegisterScope& scratch, SBit s,
549
Condition c) {
550
ma_alu(dest, imm, dest, scratch, OpAdd, s, c);
551
}
552
553
void MacroAssemblerARM::ma_add(Register src1, Register dest, SBit s,
554
Condition c) {
555
ma_alu(dest, O2Reg(src1), dest, OpAdd, s, c);
556
}
557
558
void MacroAssemblerARM::ma_add(Register src1, Register src2, Register dest,
559
SBit s, Condition c) {
560
as_alu(dest, src1, O2Reg(src2), OpAdd, s, c);
561
}
562
563
void MacroAssemblerARM::ma_add(Register src1, Operand op, Register dest, SBit s,
564
Condition c) {
565
ma_alu(src1, op, dest, OpAdd, s, c);
566
}
567
568
void MacroAssemblerARM::ma_add(Register src1, Imm32 op, Register dest,
569
AutoRegisterScope& scratch, SBit s,
570
Condition c) {
571
ma_alu(src1, op, dest, scratch, OpAdd, s, c);
572
}
573
574
// Subtract with carry.
575
void MacroAssemblerARM::ma_sbc(Imm32 imm, Register dest,
576
AutoRegisterScope& scratch, SBit s,
577
Condition c) {
578
ma_alu(dest, imm, dest, scratch, OpSbc, s, c);
579
}
580
581
void MacroAssemblerARM::ma_sbc(Register src1, Register dest, SBit s,
582
Condition c) {
583
as_alu(dest, dest, O2Reg(src1), OpSbc, s, c);
584
}
585
586
void MacroAssemblerARM::ma_sbc(Register src1, Register src2, Register dest,
587
SBit s, Condition c) {
588
as_alu(dest, src1, O2Reg(src2), OpSbc, s, c);
589
}
590
591
// Subtract.
592
void MacroAssemblerARM::ma_sub(Imm32 imm, Register dest,
593
AutoRegisterScope& scratch, SBit s,
594
Condition c) {
595
ma_alu(dest, imm, dest, scratch, OpSub, s, c);
596
}
597
598
void MacroAssemblerARM::ma_sub(Register src1, Register dest, SBit s,
599
Condition c) {
600
ma_alu(dest, Operand(src1), dest, OpSub, s, c);
601
}
602
603
void MacroAssemblerARM::ma_sub(Register src1, Register src2, Register dest,
604
SBit s, Condition c) {
605
ma_alu(src1, Operand(src2), dest, OpSub, s, c);
606
}
607
608
void MacroAssemblerARM::ma_sub(Register src1, Operand op, Register dest, SBit s,
609
Condition c) {
610
ma_alu(src1, op, dest, OpSub, s, c);
611
}
612
613
void MacroAssemblerARM::ma_sub(Register src1, Imm32 op, Register dest,
614
AutoRegisterScope& scratch, SBit s,
615
Condition c) {
616
ma_alu(src1, op, dest, scratch, OpSub, s, c);
617
}
618
619
// Reverse subtract.
620
void MacroAssemblerARM::ma_rsb(Imm32 imm, Register dest,
621
AutoRegisterScope& scratch, SBit s,
622
Condition c) {
623
ma_alu(dest, imm, dest, scratch, OpRsb, s, c);
624
}
625
626
void MacroAssemblerARM::ma_rsb(Register src1, Register dest, SBit s,
627
Condition c) {
628
as_alu(dest, src1, O2Reg(dest), OpRsb, s, c);
629
}
630
631
void MacroAssemblerARM::ma_rsb(Register src1, Register src2, Register dest,
632
SBit s, Condition c) {
633
as_alu(dest, src1, O2Reg(src2), OpRsb, s, c);
634
}
635
636
void MacroAssemblerARM::ma_rsb(Register src1, Imm32 op2, Register dest,
637
AutoRegisterScope& scratch, SBit s,
638
Condition c) {
639
ma_alu(src1, op2, dest, scratch, OpRsb, s, c);
640
}
641
642
// Reverse subtract with carry.
643
void MacroAssemblerARM::ma_rsc(Imm32 imm, Register dest,
644
AutoRegisterScope& scratch, SBit s,
645
Condition c) {
646
ma_alu(dest, imm, dest, scratch, OpRsc, s, c);
647
}
648
649
void MacroAssemblerARM::ma_rsc(Register src1, Register dest, SBit s,
650
Condition c) {
651
as_alu(dest, dest, O2Reg(src1), OpRsc, s, c);
652
}
653
654
void MacroAssemblerARM::ma_rsc(Register src1, Register src2, Register dest,
655
SBit s, Condition c) {
656
as_alu(dest, src1, O2Reg(src2), OpRsc, s, c);
657
}
658
659
// Compares/tests.
660
// Compare negative (sets condition codes as src1 + src2 would).
661
void MacroAssemblerARM::ma_cmn(Register src1, Imm32 imm,
662
AutoRegisterScope& scratch, Condition c) {
663
ma_alu(src1, imm, InvalidReg, scratch, OpCmn, SetCC, c);
664
}
665
666
void MacroAssemblerARM::ma_cmn(Register src1, Register src2, Condition c) {
667
as_alu(InvalidReg, src2, O2Reg(src1), OpCmn, SetCC, c);
668
}
669
670
void MacroAssemblerARM::ma_cmn(Register src1, Operand op, Condition c) {
671
MOZ_CRASH("Feature NYI");
672
}
673
674
// Compare (src - src2).
675
void MacroAssemblerARM::ma_cmp(Register src1, Imm32 imm,
676
AutoRegisterScope& scratch, Condition c) {
677
ma_alu(src1, imm, InvalidReg, scratch, OpCmp, SetCC, c);
678
}
679
680
void MacroAssemblerARM::ma_cmp(Register src1, ImmTag tag, Condition c) {
681
// ImmTag comparisons can always be done without use of a scratch register.
682
Imm8 negtag = Imm8(-tag.value);
683
MOZ_ASSERT(!negtag.invalid());
684
as_cmn(src1, negtag, c);
685
}
686
687
void MacroAssemblerARM::ma_cmp(Register src1, ImmWord ptr,
688
AutoRegisterScope& scratch, Condition c) {
689
ma_cmp(src1, Imm32(ptr.value), scratch, c);
690
}
691
692
void MacroAssemblerARM::ma_cmp(Register src1, ImmGCPtr ptr,
693
AutoRegisterScope& scratch, Condition c) {
694
ma_mov(ptr, scratch);
695
ma_cmp(src1, scratch, c);
696
}
697
698
void MacroAssemblerARM::ma_cmp(Register src1, Operand op,
699
AutoRegisterScope& scratch,
700
AutoRegisterScope& scratch2, Condition c) {
701
switch (op.tag()) {
702
case Operand::Tag::OP2:
703
as_cmp(src1, op.toOp2(), c);
704
break;
705
case Operand::Tag::MEM:
706
ma_ldr(op.toAddress(), scratch, scratch2);
707
as_cmp(src1, O2Reg(scratch), c);
708
break;
709
default:
710
MOZ_CRASH("trying to compare FP and integer registers");
711
}
712
}
713
714
void MacroAssemblerARM::ma_cmp(Register src1, Register src2, Condition c) {
715
as_cmp(src1, O2Reg(src2), c);
716
}
717
718
// Test for equality, (src1 ^ src2).
719
void MacroAssemblerARM::ma_teq(Register src1, Imm32 imm,
720
AutoRegisterScope& scratch, Condition c) {
721
ma_alu(src1, imm, InvalidReg, scratch, OpTeq, SetCC, c);
722
}
723
724
void MacroAssemblerARM::ma_teq(Register src1, Register src2, Condition c) {
725
as_tst(src1, O2Reg(src2), c);
726
}
727
728
void MacroAssemblerARM::ma_teq(Register src1, Operand op, Condition c) {
729
as_teq(src1, op.toOp2(), c);
730
}
731
732
// Test (src1 & src2).
733
void MacroAssemblerARM::ma_tst(Register src1, Imm32 imm,
734
AutoRegisterScope& scratch, Condition c) {
735
ma_alu(src1, imm, InvalidReg, scratch, OpTst, SetCC, c);
736
}
737
738
void MacroAssemblerARM::ma_tst(Register src1, Register src2, Condition c) {
739
as_tst(src1, O2Reg(src2), c);
740
}
741
742
void MacroAssemblerARM::ma_tst(Register src1, Operand op, Condition c) {
743
as_tst(src1, op.toOp2(), c);
744
}
745
746
void MacroAssemblerARM::ma_mul(Register src1, Register src2, Register dest) {
747
as_mul(dest, src1, src2);
748
}
749
750
void MacroAssemblerARM::ma_mul(Register src1, Imm32 imm, Register dest,
751
AutoRegisterScope& scratch) {
752
ma_mov(imm, scratch);
753
as_mul(dest, src1, scratch);
754
}
755
756
Assembler::Condition MacroAssemblerARM::ma_check_mul(Register src1,
757
Register src2,
758
Register dest,
759
AutoRegisterScope& scratch,
760
Condition cond) {
761
// TODO: this operation is illegal on armv6 and earlier
762
// if src2 == scratch or src2 == dest.
763
if (cond == Equal || cond == NotEqual) {
764
as_smull(scratch, dest, src1, src2, SetCC);
765
return cond;
766
}
767
768
if (cond == Overflow) {
769
as_smull(scratch, dest, src1, src2);
770
as_cmp(scratch, asr(dest, 31));
771
return NotEqual;
772
}
773
774
MOZ_CRASH("Condition NYI");
775
}
776
777
Assembler::Condition MacroAssemblerARM::ma_check_mul(Register src1, Imm32 imm,
778
Register dest,
779
AutoRegisterScope& scratch,
780
Condition cond) {
781
ma_mov(imm, scratch);
782
783
if (cond == Equal || cond == NotEqual) {
784
as_smull(scratch, dest, scratch, src1, SetCC);
785
return cond;
786
}
787
788
if (cond == Overflow) {
789
as_smull(scratch, dest, scratch, src1);
790
as_cmp(scratch, asr(dest, 31));
791
return NotEqual;
792
}
793
794
MOZ_CRASH("Condition NYI");
795
}
796
797
void MacroAssemblerARM::ma_umull(Register src1, Imm32 imm, Register destHigh,
798
Register destLow, AutoRegisterScope& scratch) {
799
ma_mov(imm, scratch);
800
as_umull(destHigh, destLow, src1, scratch);
801
}
802
803
void MacroAssemblerARM::ma_umull(Register src1, Register src2,
804
Register destHigh, Register destLow) {
805
as_umull(destHigh, destLow, src1, src2);
806
}
807
808
void MacroAssemblerARM::ma_mod_mask(Register src, Register dest, Register hold,
809
Register tmp, AutoRegisterScope& scratch,
810
AutoRegisterScope& scratch2,
811
int32_t shift) {
812
// We wish to compute x % (1<<y) - 1 for a known constant, y.
813
//
814
// 1. Let b = (1<<y) and C = (1<<y)-1, then think of the 32 bit dividend as
815
// a number in base b, namely c_0*1 + c_1*b + c_2*b^2 ... c_n*b^n
816
//
817
// 2. Since both addition and multiplication commute with modulus:
818
// x % C == (c_0 + c_1*b + ... + c_n*b^n) % C ==
819
// (c_0 % C) + (c_1%C) * (b % C) + (c_2 % C) * (b^2 % C)...
820
//
821
// 3. Since b == C + 1, b % C == 1, and b^n % C == 1 the whole thing
822
// simplifies to: c_0 + c_1 + c_2 ... c_n % C
823
//
824
// Each c_n can easily be computed by a shift/bitextract, and the modulus
825
// can be maintained by simply subtracting by C whenever the number gets
826
// over C.
827
int32_t mask = (1 << shift) - 1;
828
Label head;
829
830
// Register 'hold' holds -1 if the value was negative, 1 otherwise. The
831
// scratch reg holds the remaining bits that have not been processed lr
832
// serves as a temporary location to store extracted bits into as well as
833
// holding the trial subtraction as a temp value dest is the accumulator
834
// (and holds the final result)
835
//
836
// Move the whole value into tmp, setting the codition codes so we can muck
837
// with them later.
838
as_mov(tmp, O2Reg(src), SetCC);
839
// Zero out the dest.
840
ma_mov(Imm32(0), dest);
841
// Set the hold appropriately.
842
ma_mov(Imm32(1), hold);
843
ma_mov(Imm32(-1), hold, Signed);
844
as_rsb(tmp, tmp, Imm8(0), SetCC, Signed);
845
846
// Begin the main loop.
847
bind(&head);
848
{
849
// Extract the bottom bits.
850
ma_and(Imm32(mask), tmp, scratch, scratch2);
851
// Add those bits to the accumulator.
852
ma_add(scratch, dest, dest);
853
// Do a trial subtraction, this is the same operation as cmp, but we store
854
// the dest.
855
ma_sub(dest, Imm32(mask), scratch, scratch2, SetCC);
856
// If (sum - C) > 0, store sum - C back into sum, thus performing a modulus.
857
ma_mov(scratch, dest, LeaveCC, NotSigned);
858
// Get rid of the bits that we extracted before, and set the condition
859
// codes.
860
as_mov(tmp, lsr(tmp, shift), SetCC);
861
// If the shift produced zero, finish, otherwise, continue in the loop.
862
ma_b(&head, NonZero);
863
}
864
865
// Check the hold to see if we need to negate the result. Hold can only be
866
// 1 or -1, so this will never set the 0 flag.
867
as_cmp(hold, Imm8(0));
868
// If the hold was non-zero, negate the result to be in line with what JS
869
// wants this will set the condition codes if we try to negate.
870
as_rsb(dest, dest, Imm8(0), SetCC, Signed);
871
// Since the Zero flag is not set by the compare, we can *only* set the Zero
872
// flag in the rsb, so Zero is set iff we negated zero (e.g. the result of
873
// the computation was -0.0).
874
}
875
876
void MacroAssemblerARM::ma_smod(Register num, Register div, Register dest,
877
AutoRegisterScope& scratch) {
878
as_sdiv(scratch, num, div);
879
as_mls(dest, num, scratch, div);
880
}
881
882
void MacroAssemblerARM::ma_umod(Register num, Register div, Register dest,
883
AutoRegisterScope& scratch) {
884
as_udiv(scratch, num, div);
885
as_mls(dest, num, scratch, div);
886
}
887
888
// Division
889
void MacroAssemblerARM::ma_sdiv(Register num, Register div, Register dest,
890
Condition cond) {
891
as_sdiv(dest, num, div, cond);
892
}
893
894
void MacroAssemblerARM::ma_udiv(Register num, Register div, Register dest,
895
Condition cond) {
896
as_udiv(dest, num, div, cond);
897
}
898
899
// Miscellaneous instructions.
900
void MacroAssemblerARM::ma_clz(Register src, Register dest, Condition cond) {
901
as_clz(dest, src, cond);
902
}
903
904
void MacroAssemblerARM::ma_ctz(Register src, Register dest,
905
AutoRegisterScope& scratch) {
906
// int c = __clz(a & -a);
907
// return a ? 31 - c : c;
908
as_rsb(scratch, src, Imm8(0), SetCC);
909
as_and(dest, src, O2Reg(scratch), LeaveCC);
910
as_clz(dest, dest);
911
as_rsb(dest, dest, Imm8(0x1F), LeaveCC, Assembler::NotEqual);
912
}
913
914
// Memory.
915
// Shortcut for when we know we're transferring 32 bits of data.
916
void MacroAssemblerARM::ma_dtr(LoadStore ls, Register rn, Imm32 offset,
917
Register rt, AutoRegisterScope& scratch,
918
Index mode, Assembler::Condition cc) {
919
ma_dataTransferN(ls, 32, true, rn, offset, rt, scratch, mode, cc);
920
}
921
922
void MacroAssemblerARM::ma_dtr(LoadStore ls, Register rt, const Address& addr,
923
AutoRegisterScope& scratch, Index mode,
924
Condition cc) {
925
ma_dataTransferN(ls, 32, true, addr.base, Imm32(addr.offset), rt, scratch,
926
mode, cc);
927
}
928
929
void MacroAssemblerARM::ma_str(Register rt, DTRAddr addr, Index mode,
930
Condition cc) {
931
as_dtr(IsStore, 32, mode, rt, addr, cc);
932
}
933
934
void MacroAssemblerARM::ma_str(Register rt, const Address& addr,
935
AutoRegisterScope& scratch, Index mode,
936
Condition cc) {
937
ma_dtr(IsStore, rt, addr, scratch, mode, cc);
938
}
939
940
void MacroAssemblerARM::ma_strd(Register rt, DebugOnly<Register> rt2,
941
EDtrAddr addr, Index mode, Condition cc) {
942
MOZ_ASSERT((rt.code() & 1) == 0);
943
MOZ_ASSERT(rt2.value.code() == rt.code() + 1);
944
as_extdtr(IsStore, 64, true, mode, rt, addr, cc);
945
}
946
947
void MacroAssemblerARM::ma_ldr(DTRAddr addr, Register rt, Index mode,
948
Condition cc) {
949
as_dtr(IsLoad, 32, mode, rt, addr, cc);
950
}
951
952
void MacroAssemblerARM::ma_ldr(const Address& addr, Register rt,
953
AutoRegisterScope& scratch, Index mode,
954
Condition cc) {
955
ma_dtr(IsLoad, rt, addr, scratch, mode, cc);
956
}
957
958
void MacroAssemblerARM::ma_ldrb(DTRAddr addr, Register rt, Index mode,
959
Condition cc) {
960
as_dtr(IsLoad, 8, mode, rt, addr, cc);
961
}
962
963
void MacroAssemblerARM::ma_ldrsh(EDtrAddr addr, Register rt, Index mode,
964
Condition cc) {
965
as_extdtr(IsLoad, 16, true, mode, rt, addr, cc);
966
}
967
968
void MacroAssemblerARM::ma_ldrh(EDtrAddr addr, Register rt, Index mode,
969
Condition cc) {
970
as_extdtr(IsLoad, 16, false, mode, rt, addr, cc);
971
}
972
973
void MacroAssemblerARM::ma_ldrsb(EDtrAddr addr, Register rt, Index mode,
974
Condition cc) {
975
as_extdtr(IsLoad, 8, true, mode, rt, addr, cc);
976
}
977
978
void MacroAssemblerARM::ma_ldrd(EDtrAddr addr, Register rt,
979
DebugOnly<Register> rt2, Index mode,
980
Condition cc) {
981
MOZ_ASSERT((rt.code() & 1) == 0);
982
MOZ_ASSERT(rt2.value.code() == rt.code() + 1);
983
MOZ_ASSERT(addr.maybeOffsetRegister() !=
984
rt); // Undefined behavior if rm == rt/rt2.
985
MOZ_ASSERT(addr.maybeOffsetRegister() != rt2);
986
as_extdtr(IsLoad, 64, true, mode, rt, addr, cc);
987
}
988
989
void MacroAssemblerARM::ma_strh(Register rt, EDtrAddr addr, Index mode,
990
Condition cc) {
991
as_extdtr(IsStore, 16, false, mode, rt, addr, cc);
992
}
993
994
void MacroAssemblerARM::ma_strb(Register rt, DTRAddr addr, Index mode,
995
Condition cc) {
996
as_dtr(IsStore, 8, mode, rt, addr, cc);
997
}
998
999
// Specialty for moving N bits of data, where n == 8,16,32,64.
1000
BufferOffset MacroAssemblerARM::ma_dataTransferN(
1001
LoadStore ls, int size, bool IsSigned, Register rn, Register rm,
1002
Register rt, AutoRegisterScope& scratch, Index mode,
1003
Assembler::Condition cc, Scale scale) {
1004
MOZ_ASSERT(size == 8 || size == 16 || size == 32 || size == 64);
1005
1006
if (size == 32 || (size == 8 && !IsSigned)) {
1007
return as_dtr(ls, size, mode, rt,
1008
DTRAddr(rn, DtrRegImmShift(rm, LSL, scale)), cc);
1009
}
1010
1011
if (scale != TimesOne) {
1012
ma_lsl(Imm32(scale), rm, scratch);
1013
rm = scratch;
1014
}
1015
1016
return as_extdtr(ls, size, IsSigned, mode, rt, EDtrAddr(rn, EDtrOffReg(rm)),
1017
cc);
1018
}
1019
1020
// No scratch register is required if scale is TimesOne.
1021
BufferOffset MacroAssemblerARM::ma_dataTransferN(LoadStore ls, int size,
1022
bool IsSigned, Register rn,
1023
Register rm, Register rt,
1024
Index mode,
1025
Assembler::Condition cc) {
1026
MOZ_ASSERT(size == 8 || size == 16 || size == 32 || size == 64);
1027
if (size == 32 || (size == 8 && !IsSigned)) {
1028
return as_dtr(ls, size, mode, rt,
1029
DTRAddr(rn, DtrRegImmShift(rm, LSL, TimesOne)), cc);
1030
}
1031
return as_extdtr(ls, size, IsSigned, mode, rt, EDtrAddr(rn, EDtrOffReg(rm)),
1032
cc);
1033
}
1034
1035
BufferOffset MacroAssemblerARM::ma_dataTransferN(LoadStore ls, int size,
1036
bool IsSigned, Register rn,
1037
Imm32 offset, Register rt,
1038
AutoRegisterScope& scratch,
1039
Index mode,
1040
Assembler::Condition cc) {
1041
MOZ_ASSERT(!(ls == IsLoad && mode == PostIndex && rt == pc),
1042
"Large-offset PostIndex loading into PC requires special logic: "
1043
"see ma_popn_pc().");
1044
1045
int off = offset.value;
1046
1047
// We can encode this as a standard ldr.
1048
if (size == 32 || (size == 8 && !IsSigned)) {
1049
if (off < 4096 && off > -4096) {
1050
// This encodes as a single instruction, Emulating mode's behavior
1051
// in a multi-instruction sequence is not necessary.
1052
return as_dtr(ls, size, mode, rt, DTRAddr(rn, DtrOffImm(off)), cc);
1053
}
1054
1055
// We cannot encode this offset in a single ldr. For mode == index,
1056
// try to encode it as |add scratch, base, imm; ldr dest, [scratch,
1057
// +offset]|. This does not wark for mode == PreIndex or mode == PostIndex.
1058
// PreIndex is simple, just do the add into the base register first,
1059
// then do a PreIndex'ed load. PostIndexed loads can be tricky.
1060
// Normally, doing the load with an index of 0, then doing an add would
1061
// work, but if the destination is the PC, you don't get to execute the
1062
// instruction after the branch, which will lead to the base register
1063
// not being updated correctly. Explicitly handle this case, without
1064
// doing anything fancy, then handle all of the other cases.
1065
1066
// mode == Offset
1067
// add scratch, base, offset_hi
1068
// ldr dest, [scratch, +offset_lo]
1069
//
1070
// mode == PreIndex
1071
// add base, base, offset_hi
1072
// ldr dest, [base, +offset_lo]!
1073
1074
int bottom = off & 0xfff;
1075
int neg_bottom = 0x1000 - bottom;
1076
1077
MOZ_ASSERT(rn != scratch);
1078
MOZ_ASSERT(mode != PostIndex);
1079
1080
// At this point, both off - bottom and off + neg_bottom will be
1081
// reasonable-ish quantities.
1082
//
1083
// Note a neg_bottom of 0x1000 can not be encoded as an immediate
1084
// negative offset in the instruction and this occurs when bottom is
1085
// zero, so this case is guarded against below.
1086
if (off < 0) {
1087
Operand2 sub_off = Imm8(-(off - bottom)); // sub_off = bottom - off
1088
if (!sub_off.invalid()) {
1089
// - sub_off = off - bottom
1090
as_sub(scratch, rn, sub_off, LeaveCC, cc);
1091
return as_dtr(ls, size, Offset, rt, DTRAddr(scratch, DtrOffImm(bottom)),
1092
cc);
1093
}
1094
1095
// sub_off = -neg_bottom - off
1096
sub_off = Imm8(-(off + neg_bottom));
1097
if (!sub_off.invalid() && bottom != 0) {
1098
// Guarded against by: bottom != 0
1099
MOZ_ASSERT(neg_bottom < 0x1000);
1100
// - sub_off = neg_bottom + off
1101
as_sub(scratch, rn, sub_off, LeaveCC, cc);
1102
return as_dtr(ls, size, Offset, rt,
1103
DTRAddr(scratch, DtrOffImm(-neg_bottom)), cc);
1104
}
1105
} else {
1106
// sub_off = off - bottom
1107
Operand2 sub_off = Imm8(off - bottom);
1108
if (!sub_off.invalid()) {
1109
// sub_off = off - bottom
1110
as_add(scratch, rn, sub_off, LeaveCC, cc);
1111
return as_dtr(ls, size, Offset, rt, DTRAddr(scratch, DtrOffImm(bottom)),
1112
cc);
1113
}
1114
1115
// sub_off = neg_bottom + off
1116
sub_off = Imm8(off + neg_bottom);
1117
if (!sub_off.invalid() && bottom != 0) {
1118
// Guarded against by: bottom != 0
1119
MOZ_ASSERT(neg_bottom < 0x1000);
1120
// sub_off = neg_bottom + off
1121
as_add(scratch, rn, sub_off, LeaveCC, cc);
1122
return as_dtr(ls, size, Offset, rt,
1123
DTRAddr(scratch, DtrOffImm(-neg_bottom)), cc);
1124
}
1125
}
1126
1127
ma_mov(offset, scratch);
1128
return as_dtr(ls, size, mode, rt,
1129
DTRAddr(rn, DtrRegImmShift(scratch, LSL, 0)));
1130
} else {
1131
// Should attempt to use the extended load/store instructions.
1132
if (off < 256 && off > -256) {
1133
return as_extdtr(ls, size, IsSigned, mode, rt,
1134
EDtrAddr(rn, EDtrOffImm(off)), cc);
1135
}
1136
1137
// We cannot encode this offset in a single extldr. Try to encode it as
1138
// an add scratch, base, imm; extldr dest, [scratch, +offset].
1139
int bottom = off & 0xff;
1140
int neg_bottom = 0x100 - bottom;
1141
// At this point, both off - bottom and off + neg_bottom will be
1142
// reasonable-ish quantities.
1143
//
1144
// Note a neg_bottom of 0x100 can not be encoded as an immediate
1145
// negative offset in the instruction and this occurs when bottom is
1146
// zero, so this case is guarded against below.
1147
if (off < 0) {
1148
// sub_off = bottom - off
1149
Operand2 sub_off = Imm8(-(off - bottom));
1150
if (!sub_off.invalid()) {
1151
// - sub_off = off - bottom
1152
as_sub(scratch, rn, sub_off, LeaveCC, cc);
1153
return as_extdtr(ls, size, IsSigned, Offset, rt,
1154
EDtrAddr(scratch, EDtrOffImm(bottom)), cc);
1155
}
1156
// sub_off = -neg_bottom - off
1157
sub_off = Imm8(-(off + neg_bottom));
1158
if (!sub_off.invalid() && bottom != 0) {
1159
// Guarded against by: bottom != 0
1160
MOZ_ASSERT(neg_bottom < 0x100);
1161
// - sub_off = neg_bottom + off
1162
as_sub(scratch, rn, sub_off, LeaveCC, cc);
1163
return as_extdtr(ls, size, IsSigned, Offset, rt,
1164
EDtrAddr(scratch, EDtrOffImm(-neg_bottom)), cc);
1165
}
1166
} else {
1167
// sub_off = off - bottom
1168
Operand2 sub_off = Imm8(off - bottom);
1169
if (!sub_off.invalid()) {
1170
// sub_off = off - bottom
1171
as_add(scratch, rn, sub_off, LeaveCC, cc);
1172
return as_extdtr(ls, size, IsSigned, Offset, rt,
1173
EDtrAddr(scratch, EDtrOffImm(bottom)), cc);
1174
}
1175
// sub_off = neg_bottom + off
1176
sub_off = Imm8(off + neg_bottom);
1177
if (!sub_off.invalid() && bottom != 0) {
1178
// Guarded against by: bottom != 0
1179
MOZ_ASSERT(neg_bottom < 0x100);
1180
// sub_off = neg_bottom + off
1181
as_add(scratch, rn, sub_off, LeaveCC, cc);
1182
return as_extdtr(ls, size, IsSigned, Offset, rt,
1183
EDtrAddr(scratch, EDtrOffImm(-neg_bottom)), cc);
1184
}
1185
}
1186
ma_mov(offset, scratch);
1187
return as_extdtr(ls, size, IsSigned, mode, rt,
1188
EDtrAddr(rn, EDtrOffReg(scratch)), cc);
1189
}
1190
}
1191
1192
void MacroAssemblerARM::ma_pop(Register r) {
1193
as_dtr(IsLoad, 32, PostIndex, r, DTRAddr(sp, DtrOffImm(4)));
1194
}
1195
1196
void MacroAssemblerARM::ma_popn_pc(Imm32 n, AutoRegisterScope& scratch,
1197
AutoRegisterScope& scratch2) {
1198
// pc <- [sp]; sp += n
1199
int32_t nv = n.value;
1200
1201
if (nv < 4096 && nv >= -4096) {
1202
as_dtr(IsLoad, 32, PostIndex, pc, DTRAddr(sp, DtrOffImm(nv)));
1203
} else {
1204
ma_mov(sp, scratch);
1205
ma_add(Imm32(n), sp, scratch2);
1206
as_dtr(IsLoad, 32, Offset, pc, DTRAddr(scratch, DtrOffImm(0)));
1207
}
1208
}
1209
1210
void MacroAssemblerARM::ma_push(Register r) {
1211
MOZ_ASSERT(r != sp, "Use ma_push_sp().");
1212
as_dtr(IsStore, 32, PreIndex, r, DTRAddr(sp, DtrOffImm(-4)));
1213
}
1214
1215
void MacroAssemblerARM::ma_push_sp(Register r, AutoRegisterScope& scratch) {
1216
// Pushing sp is not well-defined: use two instructions.
1217
MOZ_ASSERT(r == sp);
1218
ma_mov(sp, scratch);
1219
as_dtr(IsStore, 32, PreIndex, scratch, DTRAddr(sp, DtrOffImm(-4)));
1220
}
1221
1222
void MacroAssemblerARM::ma_vpop(VFPRegister r) {
1223
startFloatTransferM(IsLoad, sp, IA, WriteBack);
1224
transferFloatReg(r);
1225
finishFloatTransfer();
1226
}
1227
1228
void MacroAssemblerARM::ma_vpush(VFPRegister r) {
1229
startFloatTransferM(IsStore, sp, DB, WriteBack);
1230
transferFloatReg(r);
1231
finishFloatTransfer();
1232
}
1233
1234
// Barriers
1235
void MacroAssemblerARM::ma_dmb(BarrierOption option) {
1236
if (HasDMBDSBISB()) {
1237
as_dmb(option);
1238
} else {
1239
as_dmb_trap();
1240
}
1241
}
1242
1243
void MacroAssemblerARM::ma_dsb(BarrierOption option) {
1244
if (HasDMBDSBISB()) {
1245
as_dsb(option);
1246
} else {
1247
as_dsb_trap();
1248
}
1249
}
1250
1251
// Branches when done from within arm-specific code.
1252
BufferOffset MacroAssemblerARM::ma_b(Label* dest, Assembler::Condition c) {
1253
return as_b(dest, c);
1254
}
1255
1256
void MacroAssemblerARM::ma_bx(Register dest, Assembler::Condition c) {
1257
as_bx(dest, c);
1258
}
1259
1260
void MacroAssemblerARM::ma_b(void* target, Assembler::Condition c) {
1261
// An immediate pool is used for easier patching.
1262
as_Imm32Pool(pc, uint32_t(target), c);
1263
}
1264
1265
// This is almost NEVER necessary: we'll basically never be calling a label,
1266
// except possibly in the crazy bailout-table case.
1267
void MacroAssemblerARM::ma_bl(Label* dest, Assembler::Condition c) {
1268
as_bl(dest, c);
1269
}
1270
1271
void MacroAssemblerARM::ma_blx(Register reg, Assembler::Condition c) {
1272
as_blx(reg, c);
1273
}
1274
1275
// VFP/ALU
1276
void MacroAssemblerARM::ma_vadd(FloatRegister src1, FloatRegister src2,
1277
FloatRegister dst) {
1278
as_vadd(VFPRegister(dst), VFPRegister(src1), VFPRegister(src2));
1279
}
1280
1281
void MacroAssemblerARM::ma_vadd_f32(FloatRegister src1, FloatRegister src2,
1282
FloatRegister dst) {
1283
as_vadd(VFPRegister(dst).singleOverlay(), VFPRegister(src1).singleOverlay(),
1284
VFPRegister(src2).singleOverlay());
1285
}
1286
1287
void MacroAssemblerARM::ma_vsub(FloatRegister src1, FloatRegister src2,
1288
FloatRegister dst) {
1289
as_vsub(VFPRegister(dst), VFPRegister(src1), VFPRegister(src2));
1290
}
1291
1292
void MacroAssemblerARM::ma_vsub_f32(FloatRegister src1, FloatRegister src2,
1293
FloatRegister dst) {
1294
as_vsub(VFPRegister(dst).singleOverlay(), VFPRegister(src1).singleOverlay(),
1295
VFPRegister(src2).singleOverlay());
1296
}
1297
1298
void MacroAssemblerARM::ma_vmul(FloatRegister src1, FloatRegister src2,
1299
FloatRegister dst) {
1300
as_vmul(VFPRegister(dst), VFPRegister(src1), VFPRegister(src2));
1301
}
1302
1303
void MacroAssemblerARM::ma_vmul_f32(FloatRegister src1, FloatRegister src2,
1304
FloatRegister dst) {
1305
as_vmul(VFPRegister(dst).singleOverlay(), VFPRegister(src1).singleOverlay(),
1306
VFPRegister(src2).singleOverlay());
1307
}
1308
1309
void MacroAssemblerARM::ma_vdiv(FloatRegister src1, FloatRegister src2,
1310
FloatRegister dst) {
1311
as_vdiv(VFPRegister(dst), VFPRegister(src1), VFPRegister(src2));
1312
}
1313
1314
void MacroAssemblerARM::ma_vdiv_f32(FloatRegister src1, FloatRegister src2,
1315
FloatRegister dst) {
1316
as_vdiv(VFPRegister(dst).singleOverlay(), VFPRegister(src1).singleOverlay(),
1317
VFPRegister(src2).singleOverlay());
1318
}
1319
1320
void MacroAssemblerARM::ma_vmov(FloatRegister src, FloatRegister dest,
1321
Condition cc) {
1322
as_vmov(dest, src, cc);
1323
}
1324
1325
void MacroAssemblerARM::ma_vmov_f32(FloatRegister src, FloatRegister dest,
1326
Condition cc) {
1327
as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(),
1328
cc);
1329
}
1330
1331
void MacroAssemblerARM::ma_vneg(FloatRegister src, FloatRegister dest,
1332
Condition cc) {
1333
as_vneg(dest, src, cc);
1334
}
1335
1336
void MacroAssemblerARM::ma_vneg_f32(FloatRegister src, FloatRegister dest,
1337
Condition cc) {
1338
as_vneg(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(),
1339
cc);
1340
}
1341
1342
void MacroAssemblerARM::ma_vabs(FloatRegister src, FloatRegister dest,
1343
Condition cc) {
1344
as_vabs(dest, src, cc);
1345
}
1346
1347
void MacroAssemblerARM::ma_vabs_f32(FloatRegister src, FloatRegister dest,
1348
Condition cc) {
1349
as_vabs(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(),
1350
cc);
1351
}
1352
1353
void MacroAssemblerARM::ma_vsqrt(FloatRegister src, FloatRegister dest,
1354
Condition cc) {
1355
as_vsqrt(dest, src, cc);
1356
}
1357
1358
void MacroAssemblerARM::ma_vsqrt_f32(FloatRegister src, FloatRegister dest,
1359
Condition cc) {
1360
as_vsqrt(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(),
1361
cc);
1362
}
1363
1364
static inline uint32_t DoubleHighWord(double d) {
1365
return static_cast<uint32_t>(BitwiseCast<uint64_t>(d) >> 32);
1366
}
1367
1368
static inline uint32_t DoubleLowWord(double d) {
1369
return static_cast<uint32_t>(BitwiseCast<uint64_t>(d)) & uint32_t(0xffffffff);
1370
}
1371
1372
void MacroAssemblerARM::ma_vimm(double value, FloatRegister dest,
1373
Condition cc) {
1374
if (HasVFPv3()) {
1375
if (DoubleLowWord(value) == 0) {
1376
if (DoubleHighWord(value) == 0) {
1377
// To zero a register, load 1.0, then execute dN <- dN - dN
1378
as_vimm(dest, VFPImm::One, cc);
1379
as_vsub(dest, dest, dest, cc);
1380
return;
1381
}
1382
1383
VFPImm enc(DoubleHighWord(value));
1384
if (enc.isValid()) {
1385
as_vimm(dest, enc, cc);
1386
return;
1387
}
1388
}
1389
}
1390
// Fall back to putting the value in a pool.
1391
as_FImm64Pool(dest, value, cc);
1392
}
1393
1394
void MacroAssemblerARM::ma_vimm_f32(float value, FloatRegister dest,
1395
Condition cc) {
1396
VFPRegister vd = VFPRegister(dest).singleOverlay();
1397
if (HasVFPv3()) {
1398
if (IsPositiveZero(value)) {
1399
// To zero a register, load 1.0, then execute sN <- sN - sN.
1400
as_vimm(vd, VFPImm::One, cc);
1401
as_vsub(vd, vd, vd, cc);
1402
return;
1403
}
1404
1405
// Note that the vimm immediate float32 instruction encoding differs
1406
// from the vimm immediate double encoding, but this difference matches
1407
// the difference in the floating point formats, so it is possible to
1408
// convert the float32 to a double and then use the double encoding
1409
// paths. It is still necessary to firstly check that the double low
1410
// word is zero because some float32 numbers set these bits and this can
1411
// not be ignored.
1412
double doubleValue(value);
1413
if (DoubleLowWord(doubleValue) == 0) {
1414
VFPImm enc(DoubleHighWord(doubleValue));
1415
if (enc.isValid()) {
1416
as_vimm(vd, enc, cc);
1417
return;
1418
}
1419
}
1420
}
1421
1422
// Fall back to putting the value in a pool.
1423
as_FImm32Pool(vd, value, cc);
1424
}
1425
1426
void MacroAssemblerARM::ma_vcmp(FloatRegister src1, FloatRegister src2,
1427
Condition cc) {
1428
as_vcmp(VFPRegister(src1), VFPRegister(src2), cc);
1429
}
1430
1431
void MacroAssemblerARM::ma_vcmp_f32(FloatRegister src1, FloatRegister src2,
1432
Condition cc) {
1433
as_vcmp(VFPRegister(src1).singleOverlay(), VFPRegister(src2).singleOverlay(),
1434
cc);
1435
}
1436
1437
void MacroAssemblerARM::ma_vcmpz(FloatRegister src1, Condition cc) {
1438
as_vcmpz(VFPRegister(src1), cc);
1439
}
1440
1441
void MacroAssemblerARM::ma_vcmpz_f32(FloatRegister src1, Condition cc) {
1442
as_vcmpz(VFPRegister(src1).singleOverlay(), cc);
1443
}
1444
1445
void MacroAssemblerARM::ma_vcvt_F64_I32(FloatRegister src, FloatRegister dest,
1446
Condition cc) {
1447
MOZ_ASSERT(src.isDouble());
1448
MOZ_ASSERT(dest.isSInt());
1449
as_vcvt(dest, src, false, cc);
1450
}
1451
1452
void MacroAssemblerARM::ma_vcvt_F64_U32(FloatRegister src, FloatRegister dest,
1453
Condition cc) {
1454
MOZ_ASSERT(src.isDouble());
1455
MOZ_ASSERT(dest.isUInt());
1456
as_vcvt(dest, src, false, cc);
1457
}
1458
1459
void MacroAssemblerARM::ma_vcvt_I32_F64(FloatRegister src, FloatRegister dest,
1460
Condition cc) {
1461
MOZ_ASSERT(src.isSInt());
1462
MOZ_ASSERT(dest.isDouble());
1463
as_vcvt(dest, src, false, cc);
1464
}
1465
1466
void MacroAssemblerARM::ma_vcvt_U32_F64(FloatRegister src, FloatRegister dest,
1467
Condition cc) {
1468
MOZ_ASSERT(src.isUInt());
1469
MOZ_ASSERT(dest.isDouble());
1470
as_vcvt(dest, src, false, cc);
1471
}
1472
1473
void MacroAssemblerARM::ma_vcvt_F32_I32(FloatRegister src, FloatRegister dest,
1474
Condition cc) {
1475
MOZ_ASSERT(src.isSingle());
1476
MOZ_ASSERT(dest.isSInt());
1477
as_vcvt(VFPRegister(dest).sintOverlay(), VFPRegister(src).singleOverlay(),
1478
false, cc);
1479
}
1480
1481
void MacroAssemblerARM::ma_vcvt_F32_U32(FloatRegister src, FloatRegister dest,
1482
Condition cc) {
1483
MOZ_ASSERT(src.isSingle());
1484
MOZ_ASSERT(dest.isUInt());
1485
as_vcvt(VFPRegister(dest).uintOverlay(), VFPRegister(src).singleOverlay(),
1486
false, cc);
1487
}
1488
1489
void MacroAssemblerARM::ma_vcvt_I32_F32(FloatRegister src, FloatRegister dest,
1490
Condition cc) {
1491
MOZ_ASSERT(src.isSInt());
1492
MOZ_ASSERT(dest.isSingle());
1493
as_vcvt(VFPRegister(dest).singleOverlay(), VFPRegister(src).sintOverlay(),
1494
false, cc);
1495
}
1496
1497
void MacroAssemblerARM::ma_vcvt_U32_F32(FloatRegister src, FloatRegister dest,
1498
Condition cc) {
1499
MOZ_ASSERT(src.isUInt());
1500
MOZ_ASSERT(dest.isSingle());
1501
as_vcvt(VFPRegister(dest).singleOverlay(), VFPRegister(src).uintOverlay(),
1502
false, cc);
1503
}
1504
1505
void MacroAssemblerARM::ma_vxfer(FloatRegister src, Register dest,
1506
Condition cc) {
1507
as_vxfer(dest, InvalidReg, VFPRegister(src).singleOverlay(), FloatToCore, cc);
1508
}
1509
1510
void MacroAssemblerARM::ma_vxfer(FloatRegister src, Register dest1,