summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/v8/test/cctest/test-disasm-arm.cc
blob: 3a2d9e8361c163fabf1b95c9bfcc22f812afe861 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#include <stdlib.h>

#include "v8.h"

#include "debug.h"
#include "disasm.h"
#include "disassembler.h"
#include "macro-assembler.h"
#include "serialize.h"
#include "cctest.h"

using namespace v8::internal;


static v8::Persistent<v8::Context> env;

static void InitializeVM() {
  if (env.IsEmpty()) {
    env = v8::Context::New();
  }
}


bool DisassembleAndCompare(byte* pc, const char* compare_string) {
  disasm::NameConverter converter;
  disasm::Disassembler disasm(converter);
  EmbeddedVector<char, 128> disasm_buffer;

  disasm.InstructionDecode(disasm_buffer, pc);

  if (strcmp(compare_string, disasm_buffer.start()) != 0) {
    fprintf(stderr,
            "expected: \n"
            "%s\n"
            "disassembled: \n"
            "%s\n\n",
            compare_string, disasm_buffer.start());
    return false;
  }
  return true;
}


// Set up V8 to a state where we can at least run the assembler and
// disassembler. Declare the variables and allocate the data structures used
// in the rest of the macros.
#define SET_UP()                                           \
  InitializeVM();                                         \
  v8::HandleScope scope;                                  \
  byte *buffer = reinterpret_cast<byte*>(malloc(4*1024)); \
  Assembler assm(Isolate::Current(), buffer, 4*1024);     \
  bool failure = false;


// This macro assembles one instruction using the preallocated assembler and
// disassembles the generated instruction, comparing the output to the expected
// value. If the comparison fails an error message is printed, but the test
// continues to run until the end.
#define COMPARE(asm_, compare_string) \
  { \
    int pc_offset = assm.pc_offset(); \
    byte *progcounter = &buffer[pc_offset]; \
    assm.asm_; \
    if (!DisassembleAndCompare(progcounter, compare_string)) failure = true; \
  }

// Force emission of any pending literals into a pool.
#define EMIT_PENDING_LITERALS() \
  assm.CheckConstPool(true, false)


// Verify that all invocations of the COMPARE macro passed successfully.
// Exit with a failure if at least one of the tests failed.
#define VERIFY_RUN() \
if (failure) { \
    V8_Fatal(__FILE__, __LINE__, "ARM Disassembler tests failed.\n"); \
  }


TEST(Type0) {
  SET_UP();

  COMPARE(and_(r0, r1, Operand(r2)),
          "e0010002       and r0, r1, r2");
  COMPARE(and_(r1, r2, Operand(r3), LeaveCC),
          "e0021003       and r1, r2, r3");
  COMPARE(and_(r2, r3, Operand(r4), SetCC),
          "e0132004       ands r2, r3, r4");
  COMPARE(and_(r3, r4, Operand(r5), LeaveCC, eq),
          "00043005       andeq r3, r4, r5");

  COMPARE(eor(r4, r5, Operand(r6, LSL, 0)),
          "e0254006       eor r4, r5, r6");
  COMPARE(eor(r4, r5, Operand(r7, LSL, 1), SetCC),
          "e0354087       eors r4, r5, r7, lsl #1");
  COMPARE(eor(r4, r5, Operand(r8, LSL, 2), LeaveCC, ne),
          "10254108       eorne r4, r5, r8, lsl #2");
  COMPARE(eor(r4, r5, Operand(r9, LSL, 3), SetCC, cs),
          "20354189       eorcss r4, r5, r9, lsl #3");

  COMPARE(sub(r5, r6, Operand(r10, LSL, 31), LeaveCC, hs),
          "20465f8a       subcs r5, r6, r10, lsl #31");
  COMPARE(sub(r5, r6, Operand(r10, LSL, 30), SetCC, cc),
          "30565f0a       subccs r5, r6, r10, lsl #30");
  COMPARE(sub(r5, r6, Operand(r10, LSL, 24), LeaveCC, lo),
          "30465c0a       subcc r5, r6, r10, lsl #24");
  COMPARE(sub(r5, r6, Operand(r10, LSL, 16), SetCC, mi),
          "4056580a       submis r5, r6, r10, lsl #16");

  COMPARE(rsb(r6, r7, Operand(fp)),
          "e067600b       rsb r6, r7, fp");
  COMPARE(rsb(r6, r7, Operand(fp, LSR, 1)),
          "e06760ab       rsb r6, r7, fp, lsr #1");
  COMPARE(rsb(r6, r7, Operand(fp, LSR, 0), SetCC),
          "e077602b       rsbs r6, r7, fp, lsr #32");
  COMPARE(rsb(r6, r7, Operand(fp, LSR, 31), LeaveCC, pl),
          "50676fab       rsbpl r6, r7, fp, lsr #31");

  COMPARE(add(r7, r8, Operand(ip, ASR, 1)),
          "e08870cc       add r7, r8, ip, asr #1");
  COMPARE(add(r7, r8, Operand(ip, ASR, 0)),
          "e088704c       add r7, r8, ip, asr #32");
  COMPARE(add(r7, r8, Operand(ip), SetCC),
          "e098700c       adds r7, r8, ip");
  COMPARE(add(r7, r8, Operand(ip, ASR, 31), SetCC, vs),
          "60987fcc       addvss r7, r8, ip, asr #31");

  COMPARE(adc(r7, fp, Operand(ip, ASR, 5)),
          "e0ab72cc       adc r7, fp, ip, asr #5");
  COMPARE(adc(r4, ip, Operand(ip, ASR, 1), LeaveCC, vc),
          "70ac40cc       adcvc r4, ip, ip, asr #1");
  COMPARE(adc(r5, sp, Operand(ip), SetCC),
          "e0bd500c       adcs r5, sp, ip");
  COMPARE(adc(r8, lr, Operand(ip, ASR, 31), SetCC, vc),
          "70be8fcc       adcvcs r8, lr, ip, asr #31");

  COMPARE(sbc(r7, r1, Operand(ip, ROR, 1), LeaveCC, hi),
          "80c170ec       sbchi r7, r1, ip, ror #1");
  COMPARE(sbc(r7, r9, Operand(ip, ROR, 4)),
          "e0c9726c       sbc r7, r9, ip, ror #4");
  COMPARE(sbc(r7, r10, Operand(ip), SetCC),
          "e0da700c       sbcs r7, r10, ip");
  COMPARE(sbc(r7, ip, Operand(ip, ROR, 31), SetCC, hi),
          "80dc7fec       sbchis r7, ip, ip, ror #31");

  COMPARE(rsc(r7, r8, Operand(ip, LSL, r0)),
          "e0e8701c       rsc r7, r8, ip, lsl r0");
  COMPARE(rsc(r7, r8, Operand(ip, LSL, r1)),
          "e0e8711c       rsc r7, r8, ip, lsl r1");
  COMPARE(rsc(r7, r8, Operand(ip), SetCC),
          "e0f8700c       rscs r7, r8, ip");
  COMPARE(rsc(r7, r8, Operand(ip, LSL, r3), SetCC, ls),
          "90f8731c       rsclss r7, r8, ip, lsl r3");

  COMPARE(tst(r7, Operand(r5, ASR, ip), ge),
          "a1170c55       tstge r7, r5, asr ip");
  COMPARE(tst(r7, Operand(r6, ASR, sp)),
          "e1170d56       tst r7, r6, asr sp");
  COMPARE(tst(r7, Operand(r7), ge),
          "a1170007       tstge r7, r7");
  COMPARE(tst(r7, Operand(r8, ASR, fp), ge),
          "a1170b58       tstge r7, r8, asr fp");

  COMPARE(teq(r7, Operand(r5, ROR, r0), lt),
          "b1370075       teqlt r7, r5, ror r0");
  COMPARE(teq(r7, Operand(r6, ROR, lr)),
          "e1370e76       teq r7, r6, ror lr");
  COMPARE(teq(r7, Operand(r7), lt),
          "b1370007       teqlt r7, r7");
  COMPARE(teq(r7, Operand(r8, ROR, r1)),
          "e1370178       teq r7, r8, ror r1");

  COMPARE(cmp(r7, Operand(r4)),
          "e1570004       cmp r7, r4");
  COMPARE(cmp(r7, Operand(r6, LSL, 1), gt),
          "c1570086       cmpgt r7, r6, lsl #1");
  COMPARE(cmp(r7, Operand(r8, LSR, 3), gt),
          "c15701a8       cmpgt r7, r8, lsr #3");
  COMPARE(cmp(r7, Operand(r8, ASR, 19)),
          "e15709c8       cmp r7, r8, asr #19");

  COMPARE(cmn(r0, Operand(r4)),
          "e1700004       cmn r0, r4");
  COMPARE(cmn(r1, Operand(r6, ROR, 1)),
          "e17100e6       cmn r1, r6, ror #1");
  COMPARE(cmn(r2, Operand(r8)),
          "e1720008       cmn r2, r8");
  COMPARE(cmn(r3, Operand(fp), le),
          "d173000b       cmnle r3, fp");

  COMPARE(orr(r7, r8, Operand(lr), LeaveCC, al),
          "e188700e       orr r7, r8, lr");
  COMPARE(orr(r7, r8, Operand(fp)),
          "e188700b       orr r7, r8, fp");
  COMPARE(orr(r7, r8, Operand(sp), SetCC),
          "e198700d       orrs r7, r8, sp");
  COMPARE(orr(r7, r8, Operand(ip), SetCC, al),
          "e198700c       orrs r7, r8, ip");

  COMPARE(mov(r0, Operand(r1), LeaveCC, eq),
          "01a00001       moveq r0, r1");
  COMPARE(mov(r0, Operand(r2)),
          "e1a00002       mov r0, r2");
  COMPARE(mov(r0, Operand(r3), SetCC),
          "e1b00003       movs r0, r3");
  COMPARE(mov(r0, Operand(r4), SetCC, pl),
          "51b00004       movpls r0, r4");

  COMPARE(bic(r0, lr, Operand(r1), LeaveCC, vs),
          "61ce0001       bicvs r0, lr, r1");
  COMPARE(bic(r0, r9, Operand(r2), LeaveCC, vc),
          "71c90002       bicvc r0, r9, r2");
  COMPARE(bic(r0, r5, Operand(r3), SetCC),
          "e1d50003       bics r0, r5, r3");
  COMPARE(bic(r0, r1, Operand(r4), SetCC, pl),
          "51d10004       bicpls r0, r1, r4");

  COMPARE(mvn(r10, Operand(r1)),
          "e1e0a001       mvn r10, r1");
  COMPARE(mvn(r9, Operand(r2)),
          "e1e09002       mvn r9, r2");
  COMPARE(mvn(r0, Operand(r3), SetCC),
          "e1f00003       mvns r0, r3");
  COMPARE(mvn(r5, Operand(r4), SetCC, cc),
          "31f05004       mvnccs r5, r4");

  // Instructions autotransformed by the assembler.
  // mov -> mvn.
  COMPARE(mov(r3, Operand(-1), LeaveCC, al),
          "e3e03000       mvn r3, #0");
  COMPARE(mov(r4, Operand(-2), SetCC, al),
          "e3f04001       mvns r4, #1");
  COMPARE(mov(r5, Operand(0x0ffffff0), SetCC, ne),
          "13f052ff       mvnnes r5, #-268435441");
  COMPARE(mov(r6, Operand(-1), LeaveCC, ne),
          "13e06000       mvnne r6, #0");

  // mvn -> mov.
  COMPARE(mvn(r3, Operand(-1), LeaveCC, al),
          "e3a03000       mov r3, #0");
  COMPARE(mvn(r4, Operand(-2), SetCC, al),
          "e3b04001       movs r4, #1");
  COMPARE(mvn(r5, Operand(0x0ffffff0), SetCC, ne),
          "13b052ff       movnes r5, #-268435441");
  COMPARE(mvn(r6, Operand(-1), LeaveCC, ne),
          "13a06000       movne r6, #0");

  // mov -> movw.
  if (CpuFeatures::IsSupported(ARMv7)) {
    COMPARE(mov(r5, Operand(0x01234), LeaveCC, ne),
            "13015234       movwne r5, #4660");
    // We only disassemble one instruction so the eor instruction is not here.
    COMPARE(eor(r5, r4, Operand(0x1234), LeaveCC, ne),
            "1301c234       movwne ip, #4660");
    // Movw can't do setcc so we don't get that here.  Mov immediate with setcc
    // is pretty strange anyway.
    COMPARE(mov(r5, Operand(0x01234), SetCC, ne),
            "159fc000       ldrne ip, [pc, #+0]");
    // Emit a literal pool now, otherwise this could be dumped later, in the
    // middle of a different test.
    EMIT_PENDING_LITERALS();

    // We only disassemble one instruction so the eor instruction is not here.
    // The eor does the setcc so we get a movw here.
    COMPARE(eor(r5, r4, Operand(0x1234), SetCC, ne),
            "1301c234       movwne ip, #4660");

    COMPARE(movt(r5, 0x4321, ne),
            "13445321       movtne r5, #17185");
    COMPARE(movw(r5, 0xabcd, eq),
            "030a5bcd       movweq r5, #43981");
  }

  // Eor doesn't have an eor-negative variant, but we can do an mvn followed by
  // an eor to get the same effect.
  COMPARE(eor(r5, r4, Operand(0xffffff34), SetCC, ne),
          "13e0c0cb       mvnne ip, #203");

  // and <-> bic.
  COMPARE(and_(r3, r5, Operand(0xfc03ffff)),
          "e3c537ff       bic r3, r5, #66846720");
  COMPARE(bic(r3, r5, Operand(0xfc03ffff)),
          "e20537ff       and r3, r5, #66846720");

  // sub <-> add.
  COMPARE(add(r3, r5, Operand(-1024)),
          "e2453b01       sub r3, r5, #1024");
  COMPARE(sub(r3, r5, Operand(-1024)),
          "e2853b01       add r3, r5, #1024");

  // cmp <-> cmn.
  COMPARE(cmp(r3, Operand(-1024)),
          "e3730b01       cmn r3, #1024");
  COMPARE(cmn(r3, Operand(-1024)),
          "e3530b01       cmp r3, #1024");

  // Miscellaneous instructions encoded as type 0.
  COMPARE(blx(ip),
          "e12fff3c       blx ip");
  COMPARE(bkpt(0),
          "e1200070       bkpt 0");
  COMPARE(bkpt(0xffff),
          "e12fff7f       bkpt 65535");
  COMPARE(clz(r6, r7),
          "e16f6f17       clz r6, r7");

  VERIFY_RUN();
}


TEST(Type1) {
  SET_UP();

  COMPARE(and_(r0, r1, Operand(0x00000000)),
          "e2010000       and r0, r1, #0");
  COMPARE(and_(r1, r2, Operand(0x00000001), LeaveCC),
          "e2021001       and r1, r2, #1");
  COMPARE(and_(r2, r3, Operand(0x00000010), SetCC),
          "e2132010       ands r2, r3, #16");
  COMPARE(and_(r3, r4, Operand(0x00000100), LeaveCC, eq),
          "02043c01       andeq r3, r4, #256");
  COMPARE(and_(r4, r5, Operand(0x00001000), SetCC, ne),
          "12154a01       andnes r4, r5, #4096");

  COMPARE(eor(r4, r5, Operand(0x00001000)),
          "e2254a01       eor r4, r5, #4096");
  COMPARE(eor(r4, r4, Operand(0x00010000), LeaveCC),
          "e2244801       eor r4, r4, #65536");
  COMPARE(eor(r4, r3, Operand(0x00100000), SetCC),
          "e2334601       eors r4, r3, #1048576");
  COMPARE(eor(r4, r2, Operand(0x01000000), LeaveCC, cs),
          "22224401       eorcs r4, r2, #16777216");
  COMPARE(eor(r4, r1, Operand(0x10000000), SetCC, cc),
          "32314201       eorccs r4, r1, #268435456");

  VERIFY_RUN();
}


TEST(Type3) {
  SET_UP();

  if (CpuFeatures::IsSupported(ARMv7)) {
    COMPARE(ubfx(r0, r1, 5, 10),
            "e7e902d1       ubfx r0, r1, #5, #10");
    COMPARE(ubfx(r1, r0, 5, 10),
            "e7e912d0       ubfx r1, r0, #5, #10");
    COMPARE(ubfx(r0, r1, 31, 1),
            "e7e00fd1       ubfx r0, r1, #31, #1");
    COMPARE(ubfx(r1, r0, 31, 1),
            "e7e01fd0       ubfx r1, r0, #31, #1");

    COMPARE(sbfx(r0, r1, 5, 10),
            "e7a902d1       sbfx r0, r1, #5, #10");
    COMPARE(sbfx(r1, r0, 5, 10),
            "e7a912d0       sbfx r1, r0, #5, #10");
    COMPARE(sbfx(r0, r1, 31, 1),
            "e7a00fd1       sbfx r0, r1, #31, #1");
    COMPARE(sbfx(r1, r0, 31, 1),
            "e7a01fd0       sbfx r1, r0, #31, #1");

    COMPARE(bfc(r0, 5, 10),
            "e7ce029f       bfc r0, #5, #10");
    COMPARE(bfc(r1, 5, 10),
            "e7ce129f       bfc r1, #5, #10");
    COMPARE(bfc(r0, 31, 1),
            "e7df0f9f       bfc r0, #31, #1");
    COMPARE(bfc(r1, 31, 1),
            "e7df1f9f       bfc r1, #31, #1");

    COMPARE(bfi(r0, r1, 5, 10),
            "e7ce0291       bfi r0, r1, #5, #10");
    COMPARE(bfi(r1, r0, 5, 10),
            "e7ce1290       bfi r1, r0, #5, #10");
    COMPARE(bfi(r0, r1, 31, 1),
            "e7df0f91       bfi r0, r1, #31, #1");
    COMPARE(bfi(r1, r0, 31, 1),
            "e7df1f90       bfi r1, r0, #31, #1");

    COMPARE(usat(r0, 1, Operand(r1)),
            "e6e10011       usat r0, #1, r1");
    COMPARE(usat(r2, 7, Operand(lr)),
            "e6e7201e       usat r2, #7, lr");
    COMPARE(usat(r3, 31, Operand(r4, LSL, 31)),
            "e6ff3f94       usat r3, #31, r4, lsl #31");
    COMPARE(usat(r8, 0, Operand(r5, ASR, 17)),
            "e6e088d5       usat r8, #0, r5, asr #17");
  }

  VERIFY_RUN();
}



TEST(Vfp) {
  SET_UP();

  if (CpuFeatures::IsSupported(VFP3)) {
    CpuFeatures::Scope scope(VFP3);
    COMPARE(vmov(d0, d1),
            "eeb00b41       vmov.f64 d0, d1");
    COMPARE(vmov(d3, d3, eq),
            "0eb03b43       vmov.f64eq d3, d3");

    COMPARE(vmov(s0, s31),
            "eeb00a6f       vmov.f32 s0, s31");
    COMPARE(vmov(s31, s0),
            "eef0fa40       vmov.f32 s31, s0");
    COMPARE(vmov(r0, s0),
            "ee100a10       vmov r0, s0");
    COMPARE(vmov(r10, s31),
            "ee1faa90       vmov r10, s31");
    COMPARE(vmov(s0, r0),
            "ee000a10       vmov s0, r0");
    COMPARE(vmov(s31, r10),
            "ee0faa90       vmov s31, r10");

    COMPARE(vabs(d0, d1),
            "eeb00bc1       vabs.f64 d0, d1");
    COMPARE(vabs(d3, d4, mi),
            "4eb03bc4       vabs.f64mi d3, d4");

    COMPARE(vneg(d0, d1),
            "eeb10b41       vneg.f64 d0, d1");
    COMPARE(vneg(d3, d4, mi),
            "4eb13b44       vneg.f64mi d3, d4");

    COMPARE(vadd(d0, d1, d2),
            "ee310b02       vadd.f64 d0, d1, d2");
    COMPARE(vadd(d3, d4, d5, mi),
            "4e343b05       vadd.f64mi d3, d4, d5");

    COMPARE(vsub(d0, d1, d2),
            "ee310b42       vsub.f64 d0, d1, d2");
    COMPARE(vsub(d3, d4, d5, ne),
            "1e343b45       vsub.f64ne d3, d4, d5");

    COMPARE(vmul(d2, d1, d0),
            "ee212b00       vmul.f64 d2, d1, d0");
    COMPARE(vmul(d6, d4, d5, cc),
            "3e246b05       vmul.f64cc d6, d4, d5");

    COMPARE(vdiv(d2, d2, d2),
            "ee822b02       vdiv.f64 d2, d2, d2");
    COMPARE(vdiv(d6, d7, d7, hi),
            "8e876b07       vdiv.f64hi d6, d7, d7");

    COMPARE(vsqrt(d0, d0),
            "eeb10bc0       vsqrt.f64 d0, d0");
    COMPARE(vsqrt(d2, d3, ne),
            "1eb12bc3       vsqrt.f64ne d2, d3");

    COMPARE(vmov(d0, 1.0),
            "eeb70b00       vmov.f64 d0, #1");
    COMPARE(vmov(d2, -13.0),
            "eeba2b0a       vmov.f64 d2, #-13");

    COMPARE(vldr(s0, r0, 0),
            "ed900a00       vldr s0, [r0 + 4*0]");
    COMPARE(vldr(s1, r1, 4),
            "edd10a01       vldr s1, [r1 + 4*1]");
    COMPARE(vldr(s15, r4, 16),
            "edd47a04       vldr s15, [r4 + 4*4]");
    COMPARE(vldr(s16, r5, 20),
            "ed958a05       vldr s16, [r5 + 4*5]");
    COMPARE(vldr(s31, r10, 1020),
            "eddafaff       vldr s31, [r10 + 4*255]");

    COMPARE(vstr(s0, r0, 0),
            "ed800a00       vstr s0, [r0 + 4*0]");
    COMPARE(vstr(s1, r1, 4),
            "edc10a01       vstr s1, [r1 + 4*1]");
    COMPARE(vstr(s15, r8, 8),
            "edc87a02       vstr s15, [r8 + 4*2]");
    COMPARE(vstr(s16, r9, 12),
            "ed898a03       vstr s16, [r9 + 4*3]");
    COMPARE(vstr(s31, r10, 1020),
            "edcafaff       vstr s31, [r10 + 4*255]");

    COMPARE(vldr(d0, r0, 0),
            "ed900b00       vldr d0, [r0 + 4*0]");
    COMPARE(vldr(d1, r1, 4),
            "ed911b01       vldr d1, [r1 + 4*1]");
    COMPARE(vldr(d15, r10, 1020),
            "ed9afbff       vldr d15, [r10 + 4*255]");
    COMPARE(vstr(d0, r0, 0),
            "ed800b00       vstr d0, [r0 + 4*0]");
    COMPARE(vstr(d1, r1, 4),
            "ed811b01       vstr d1, [r1 + 4*1]");
    COMPARE(vstr(d15, r10, 1020),
            "ed8afbff       vstr d15, [r10 + 4*255]");

    COMPARE(vmsr(r5),
            "eee15a10       vmsr FPSCR, r5");
    COMPARE(vmsr(r10, pl),
            "5ee1aa10       vmsrpl FPSCR, r10");
    COMPARE(vmsr(pc),
            "eee1fa10       vmsr FPSCR, APSR");
    COMPARE(vmrs(r5),
            "eef15a10       vmrs r5, FPSCR");
    COMPARE(vmrs(r10, ge),
            "aef1aa10       vmrsge r10, FPSCR");
    COMPARE(vmrs(pc),
            "eef1fa10       vmrs APSR, FPSCR");

    COMPARE(vstm(ia, r0, d1, d3),
            "ec801b06       vstmia r0, {d1-d3}");
    COMPARE(vldm(ia, r1, d2, d5),
            "ec912b08       vldmia r1, {d2-d5}");
    COMPARE(vstm(ia, r2, d0, d15),
            "ec820b20       vstmia r2, {d0-d15}");
    COMPARE(vldm(ia, r3, d0, d15),
            "ec930b20       vldmia r3, {d0-d15}");
    COMPARE(vstm(ia, r4, s1, s3),
            "ecc40a03       vstmia r4, {s1-s3}");
    COMPARE(vldm(ia, r5, s2, s5),
            "ec951a04       vldmia r5, {s2-s5}");
    COMPARE(vstm(ia, r6, s0, s31),
            "ec860a20       vstmia r6, {s0-s31}");
    COMPARE(vldm(ia, r7, s0, s31),
            "ec970a20       vldmia r7, {s0-s31}");
  }

  VERIFY_RUN();
}


TEST(LoadStore) {
  SET_UP();

  COMPARE(ldrb(r0, MemOperand(r1)),
          "e5d10000       ldrb r0, [r1, #+0]");
  COMPARE(ldrb(r2, MemOperand(r3, 42)),
          "e5d3202a       ldrb r2, [r3, #+42]");
  COMPARE(ldrb(r4, MemOperand(r5, -42)),
          "e555402a       ldrb r4, [r5, #-42]");
  COMPARE(ldrb(r6, MemOperand(r7, 42, PostIndex)),
          "e4d7602a       ldrb r6, [r7], #+42");
  COMPARE(ldrb(r8, MemOperand(r9, -42, PostIndex)),
          "e459802a       ldrb r8, [r9], #-42");
  COMPARE(ldrb(r10, MemOperand(fp, 42, PreIndex)),
          "e5fba02a       ldrb r10, [fp, #+42]!");
  COMPARE(ldrb(ip, MemOperand(sp, -42, PreIndex)),
          "e57dc02a       ldrb ip, [sp, #-42]!");
  COMPARE(ldrb(r0, MemOperand(r1, r2)),
          "e7d10002       ldrb r0, [r1, +r2]");
  COMPARE(ldrb(r0, MemOperand(r1, r2, NegOffset)),
          "e7510002       ldrb r0, [r1, -r2]");
  COMPARE(ldrb(r0, MemOperand(r1, r2, PostIndex)),
          "e6d10002       ldrb r0, [r1], +r2");
  COMPARE(ldrb(r0, MemOperand(r1, r2, NegPostIndex)),
          "e6510002       ldrb r0, [r1], -r2");
  COMPARE(ldrb(r0, MemOperand(r1, r2, PreIndex)),
          "e7f10002       ldrb r0, [r1, +r2]!");
  COMPARE(ldrb(r0, MemOperand(r1, r2, NegPreIndex)),
          "e7710002       ldrb r0, [r1, -r2]!");

  COMPARE(strb(r0, MemOperand(r1)),
          "e5c10000       strb r0, [r1, #+0]");
  COMPARE(strb(r2, MemOperand(r3, 42)),
          "e5c3202a       strb r2, [r3, #+42]");
  COMPARE(strb(r4, MemOperand(r5, -42)),
          "e545402a       strb r4, [r5, #-42]");
  COMPARE(strb(r6, MemOperand(r7, 42, PostIndex)),
          "e4c7602a       strb r6, [r7], #+42");
  COMPARE(strb(r8, MemOperand(r9, -42, PostIndex)),
          "e449802a       strb r8, [r9], #-42");
  COMPARE(strb(r10, MemOperand(fp, 42, PreIndex)),
          "e5eba02a       strb r10, [fp, #+42]!");
  COMPARE(strb(ip, MemOperand(sp, -42, PreIndex)),
          "e56dc02a       strb ip, [sp, #-42]!");
  COMPARE(strb(r0, MemOperand(r1, r2)),
          "e7c10002       strb r0, [r1, +r2]");
  COMPARE(strb(r0, MemOperand(r1, r2, NegOffset)),
          "e7410002       strb r0, [r1, -r2]");
  COMPARE(strb(r0, MemOperand(r1, r2, PostIndex)),
          "e6c10002       strb r0, [r1], +r2");
  COMPARE(strb(r0, MemOperand(r1, r2, NegPostIndex)),
          "e6410002       strb r0, [r1], -r2");
  COMPARE(strb(r0, MemOperand(r1, r2, PreIndex)),
          "e7e10002       strb r0, [r1, +r2]!");
  COMPARE(strb(r0, MemOperand(r1, r2, NegPreIndex)),
          "e7610002       strb r0, [r1, -r2]!");

  COMPARE(ldrh(r0, MemOperand(r1)),
          "e1d100b0       ldrh r0, [r1, #+0]");
  COMPARE(ldrh(r2, MemOperand(r3, 42)),
          "e1d322ba       ldrh r2, [r3, #+42]");
  COMPARE(ldrh(r4, MemOperand(r5, -42)),
          "e15542ba       ldrh r4, [r5, #-42]");
  COMPARE(ldrh(r6, MemOperand(r7, 42, PostIndex)),
          "e0d762ba       ldrh r6, [r7], #+42");
  COMPARE(ldrh(r8, MemOperand(r9, -42, PostIndex)),
          "e05982ba       ldrh r8, [r9], #-42");
  COMPARE(ldrh(r10, MemOperand(fp, 42, PreIndex)),
          "e1fba2ba       ldrh r10, [fp, #+42]!");
  COMPARE(ldrh(ip, MemOperand(sp, -42, PreIndex)),
          "e17dc2ba       ldrh ip, [sp, #-42]!");
  COMPARE(ldrh(r0, MemOperand(r1, r2)),
          "e19100b2       ldrh r0, [r1, +r2]");
  COMPARE(ldrh(r0, MemOperand(r1, r2, NegOffset)),
          "e11100b2       ldrh r0, [r1, -r2]");
  COMPARE(ldrh(r0, MemOperand(r1, r2, PostIndex)),
          "e09100b2       ldrh r0, [r1], +r2");
  COMPARE(ldrh(r0, MemOperand(r1, r2, NegPostIndex)),
          "e01100b2       ldrh r0, [r1], -r2");
  COMPARE(ldrh(r0, MemOperand(r1, r2, PreIndex)),
          "e1b100b2       ldrh r0, [r1, +r2]!");
  COMPARE(ldrh(r0, MemOperand(r1, r2, NegPreIndex)),
          "e13100b2       ldrh r0, [r1, -r2]!");

  COMPARE(strh(r0, MemOperand(r1)),
          "e1c100b0       strh r0, [r1, #+0]");
  COMPARE(strh(r2, MemOperand(r3, 42)),
          "e1c322ba       strh r2, [r3, #+42]");
  COMPARE(strh(r4, MemOperand(r5, -42)),
          "e14542ba       strh r4, [r5, #-42]");
  COMPARE(strh(r6, MemOperand(r7, 42, PostIndex)),
          "e0c762ba       strh r6, [r7], #+42");
  COMPARE(strh(r8, MemOperand(r9, -42, PostIndex)),
          "e04982ba       strh r8, [r9], #-42");
  COMPARE(strh(r10, MemOperand(fp, 42, PreIndex)),
          "e1eba2ba       strh r10, [fp, #+42]!");
  COMPARE(strh(ip, MemOperand(sp, -42, PreIndex)),
          "e16dc2ba       strh ip, [sp, #-42]!");
  COMPARE(strh(r0, MemOperand(r1, r2)),
          "e18100b2       strh r0, [r1, +r2]");
  COMPARE(strh(r0, MemOperand(r1, r2, NegOffset)),
          "e10100b2       strh r0, [r1, -r2]");
  COMPARE(strh(r0, MemOperand(r1, r2, PostIndex)),
          "e08100b2       strh r0, [r1], +r2");
  COMPARE(strh(r0, MemOperand(r1, r2, NegPostIndex)),
          "e00100b2       strh r0, [r1], -r2");
  COMPARE(strh(r0, MemOperand(r1, r2, PreIndex)),
          "e1a100b2       strh r0, [r1, +r2]!");
  COMPARE(strh(r0, MemOperand(r1, r2, NegPreIndex)),
          "e12100b2       strh r0, [r1, -r2]!");

  COMPARE(ldr(r0, MemOperand(r1)),
          "e5910000       ldr r0, [r1, #+0]");
  COMPARE(ldr(r2, MemOperand(r3, 42)),
          "e593202a       ldr r2, [r3, #+42]");
  COMPARE(ldr(r4, MemOperand(r5, -42)),
          "e515402a       ldr r4, [r5, #-42]");
  COMPARE(ldr(r6, MemOperand(r7, 42, PostIndex)),
          "e497602a       ldr r6, [r7], #+42");
  COMPARE(ldr(r8, MemOperand(r9, -42, PostIndex)),
          "e419802a       ldr r8, [r9], #-42");
  COMPARE(ldr(r10, MemOperand(fp, 42, PreIndex)),
          "e5bba02a       ldr r10, [fp, #+42]!");
  COMPARE(ldr(ip, MemOperand(sp, -42, PreIndex)),
          "e53dc02a       ldr ip, [sp, #-42]!");
  COMPARE(ldr(r0, MemOperand(r1, r2)),
          "e7910002       ldr r0, [r1, +r2]");
  COMPARE(ldr(r0, MemOperand(r1, r2, NegOffset)),
          "e7110002       ldr r0, [r1, -r2]");
  COMPARE(ldr(r0, MemOperand(r1, r2, PostIndex)),
          "e6910002       ldr r0, [r1], +r2");
  COMPARE(ldr(r0, MemOperand(r1, r2, NegPostIndex)),
          "e6110002       ldr r0, [r1], -r2");
  COMPARE(ldr(r0, MemOperand(r1, r2, PreIndex)),
          "e7b10002       ldr r0, [r1, +r2]!");
  COMPARE(ldr(r0, MemOperand(r1, r2, NegPreIndex)),
          "e7310002       ldr r0, [r1, -r2]!");

  COMPARE(str(r0, MemOperand(r1)),
          "e5810000       str r0, [r1, #+0]");
  COMPARE(str(r2, MemOperand(r3, 42)),
          "e583202a       str r2, [r3, #+42]");
  COMPARE(str(r4, MemOperand(r5, -42)),
          "e505402a       str r4, [r5, #-42]");
  COMPARE(str(r6, MemOperand(r7, 42, PostIndex)),
          "e487602a       str r6, [r7], #+42");
  COMPARE(str(r8, MemOperand(r9, -42, PostIndex)),
          "e409802a       str r8, [r9], #-42");
  COMPARE(str(r10, MemOperand(fp, 42, PreIndex)),
          "e5aba02a       str r10, [fp, #+42]!");
  COMPARE(str(ip, MemOperand(sp, -42, PreIndex)),
          "e52dc02a       str ip, [sp, #-42]!");
  COMPARE(str(r0, MemOperand(r1, r2)),
          "e7810002       str r0, [r1, +r2]");
  COMPARE(str(r0, MemOperand(r1, r2, NegOffset)),
          "e7010002       str r0, [r1, -r2]");
  COMPARE(str(r0, MemOperand(r1, r2, PostIndex)),
          "e6810002       str r0, [r1], +r2");
  COMPARE(str(r0, MemOperand(r1, r2, NegPostIndex)),
          "e6010002       str r0, [r1], -r2");
  COMPARE(str(r0, MemOperand(r1, r2, PreIndex)),
          "e7a10002       str r0, [r1, +r2]!");
  COMPARE(str(r0, MemOperand(r1, r2, NegPreIndex)),
          "e7210002       str r0, [r1, -r2]!");

  if (CpuFeatures::IsSupported(ARMv7)) {
    CpuFeatures::Scope scope(ARMv7);
    COMPARE(ldrd(r0, r1, MemOperand(r1)),
            "e1c100d0       ldrd r0, [r1, #+0]");
    COMPARE(ldrd(r2, r3, MemOperand(r3, 127)),
            "e1c327df       ldrd r2, [r3, #+127]");
    COMPARE(ldrd(r4, r5, MemOperand(r5, -127)),
            "e14547df       ldrd r4, [r5, #-127]");
    COMPARE(ldrd(r6, r7, MemOperand(r7, 127, PostIndex)),
            "e0c767df       ldrd r6, [r7], #+127");
    COMPARE(ldrd(r8, r9, MemOperand(r9, -127, PostIndex)),
            "e04987df       ldrd r8, [r9], #-127");
    COMPARE(ldrd(r10, fp, MemOperand(fp, 127, PreIndex)),
            "e1eba7df       ldrd r10, [fp, #+127]!");
    COMPARE(ldrd(ip, sp, MemOperand(sp, -127, PreIndex)),
            "e16dc7df       ldrd ip, [sp, #-127]!");

    COMPARE(strd(r0, r1, MemOperand(r1)),
            "e1c100f0       strd r0, [r1, #+0]");
    COMPARE(strd(r2, r3, MemOperand(r3, 127)),
            "e1c327ff       strd r2, [r3, #+127]");
    COMPARE(strd(r4, r5, MemOperand(r5, -127)),
            "e14547ff       strd r4, [r5, #-127]");
    COMPARE(strd(r6, r7, MemOperand(r7, 127, PostIndex)),
            "e0c767ff       strd r6, [r7], #+127");
    COMPARE(strd(r8, r9, MemOperand(r9, -127, PostIndex)),
            "e04987ff       strd r8, [r9], #-127");
    COMPARE(strd(r10, fp, MemOperand(fp, 127, PreIndex)),
            "e1eba7ff       strd r10, [fp, #+127]!");
    COMPARE(strd(ip, sp, MemOperand(sp, -127, PreIndex)),
            "e16dc7ff       strd ip, [sp, #-127]!");
  }

  VERIFY_RUN();
}