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