xref: /aosp_15_r20/external/XNNPACK/src/jit/aarch32-assembler.cc (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
1*4bdc9457SAndroid Build Coastguard Worker // Copyright 2021 Google LLC
2*4bdc9457SAndroid Build Coastguard Worker //
3*4bdc9457SAndroid Build Coastguard Worker // This source code is licensed under the BSD-style license found in the
4*4bdc9457SAndroid Build Coastguard Worker // LICENSE file in the root directory of this source tree.
5*4bdc9457SAndroid Build Coastguard Worker 
6*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/aarch32-assembler.h"
7*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/assembler.h"
8*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/math.h"
9*4bdc9457SAndroid Build Coastguard Worker 
10*4bdc9457SAndroid Build Coastguard Worker #include <cmath>
11*4bdc9457SAndroid Build Coastguard Worker #include <cstddef>
12*4bdc9457SAndroid Build Coastguard Worker 
13*4bdc9457SAndroid Build Coastguard Worker namespace xnnpack {
14*4bdc9457SAndroid Build Coastguard Worker namespace aarch32 {
15*4bdc9457SAndroid Build Coastguard Worker // Max value of imm for vldr/str (takes imm8, but shift right by 2 when encoding).
16*4bdc9457SAndroid Build Coastguard Worker constexpr int32_t kUint10Max = 1023;
17*4bdc9457SAndroid Build Coastguard Worker // Max value of imm that fits in ldr/str encoding (takes imm12, with a separate bit for sign).
18*4bdc9457SAndroid Build Coastguard Worker constexpr int32_t kUint12Max = 4095;
19*4bdc9457SAndroid Build Coastguard Worker 
20*4bdc9457SAndroid Build Coastguard Worker // PC register contains current address of instruction + 8 (2 instructions).
21*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kPCDelta = 8;
22*4bdc9457SAndroid Build Coastguard Worker // Constants used for checking branch offsets bounds.
23*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kInt24Max = 8388607;
24*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kInt24Min = -8388608;
25*4bdc9457SAndroid Build Coastguard Worker 
26*4bdc9457SAndroid Build Coastguard Worker // Check if a branch offset is valid, it must fit in 24 bits.
branch_offset_valid(ptrdiff_t offset)27*4bdc9457SAndroid Build Coastguard Worker bool branch_offset_valid(ptrdiff_t offset) {
28*4bdc9457SAndroid Build Coastguard Worker   return offset < kInt24Max && offset > kInt24Min;
29*4bdc9457SAndroid Build Coastguard Worker }
30*4bdc9457SAndroid Build Coastguard Worker 
invalid_register_list(DRegisterList regs)31*4bdc9457SAndroid Build Coastguard Worker bool invalid_register_list(DRegisterList regs) {
32*4bdc9457SAndroid Build Coastguard Worker   return regs.length == 0 || regs.length > 16 || regs.start.code + regs.length > 32;
33*4bdc9457SAndroid Build Coastguard Worker }
34*4bdc9457SAndroid Build Coastguard Worker 
invalid_register_list(SRegisterList regs)35*4bdc9457SAndroid Build Coastguard Worker bool invalid_register_list(SRegisterList regs) {
36*4bdc9457SAndroid Build Coastguard Worker   return regs.length == 0 || regs.start.code + regs.length > 32;
37*4bdc9457SAndroid Build Coastguard Worker }
38*4bdc9457SAndroid Build Coastguard Worker 
encode(SRegister r,uint32_t single_bit_pos,uint32_t four_bits_pos)39*4bdc9457SAndroid Build Coastguard Worker uint32_t encode(SRegister r, uint32_t single_bit_pos, uint32_t four_bits_pos) {
40*4bdc9457SAndroid Build Coastguard Worker   return r.d() << single_bit_pos | r.vd() << four_bits_pos;
41*4bdc9457SAndroid Build Coastguard Worker }
42*4bdc9457SAndroid Build Coastguard Worker 
encode(DRegister r,uint32_t single_bit_pos,uint32_t four_bits_pos)43*4bdc9457SAndroid Build Coastguard Worker uint32_t encode(DRegister r, uint32_t single_bit_pos, uint32_t four_bits_pos) {
44*4bdc9457SAndroid Build Coastguard Worker   return r.d() << single_bit_pos | r.vd() << four_bits_pos;
45*4bdc9457SAndroid Build Coastguard Worker }
46*4bdc9457SAndroid Build Coastguard Worker 
encode(DRegisterLane r,uint32_t single_bit_pos,uint32_t four_bits_pos)47*4bdc9457SAndroid Build Coastguard Worker uint32_t encode(DRegisterLane r, uint32_t single_bit_pos, uint32_t four_bits_pos) {
48*4bdc9457SAndroid Build Coastguard Worker   return r.d() << single_bit_pos | r.vd() << four_bits_pos;
49*4bdc9457SAndroid Build Coastguard Worker }
50*4bdc9457SAndroid Build Coastguard Worker 
encode(QRegister r,uint32_t single_bit_pos,uint32_t four_bits_pos)51*4bdc9457SAndroid Build Coastguard Worker uint32_t encode(QRegister r, uint32_t single_bit_pos, uint32_t four_bits_pos) {
52*4bdc9457SAndroid Build Coastguard Worker   return r.d() << single_bit_pos | r.vd() << four_bits_pos;
53*4bdc9457SAndroid Build Coastguard Worker }
54*4bdc9457SAndroid Build Coastguard Worker 
encode(SRegisterList regs,uint32_t single_bit_pos,uint32_t four_bits_pos)55*4bdc9457SAndroid Build Coastguard Worker uint32_t encode(SRegisterList regs, uint32_t single_bit_pos, uint32_t four_bits_pos) {
56*4bdc9457SAndroid Build Coastguard Worker   const SRegister r = regs.start;
57*4bdc9457SAndroid Build Coastguard Worker   return r.d() << single_bit_pos | r.vd() << four_bits_pos | regs.length;
58*4bdc9457SAndroid Build Coastguard Worker }
59*4bdc9457SAndroid Build Coastguard Worker 
encode(DRegisterList regs,uint32_t single_bit_pos,uint32_t four_bits_pos)60*4bdc9457SAndroid Build Coastguard Worker uint32_t encode(DRegisterList regs, uint32_t single_bit_pos, uint32_t four_bits_pos) {
61*4bdc9457SAndroid Build Coastguard Worker   const DRegister r = regs.start;
62*4bdc9457SAndroid Build Coastguard Worker   return r.d() << single_bit_pos | r.vd() << four_bits_pos | regs.length * 2;
63*4bdc9457SAndroid Build Coastguard Worker }
64*4bdc9457SAndroid Build Coastguard Worker 
encode_mem_puw(MemOperand op)65*4bdc9457SAndroid Build Coastguard Worker uint32_t encode_mem_puw(MemOperand op) {
66*4bdc9457SAndroid Build Coastguard Worker   return op.p() << 24 | op.u() << 23 | op.w() << 21 | op.base().code << 16;
67*4bdc9457SAndroid Build Coastguard Worker }
68*4bdc9457SAndroid Build Coastguard Worker 
69*4bdc9457SAndroid Build Coastguard Worker // Return value of 0 is invalid, indicates error.
encode_regs_length_to_type(DRegisterList regs)70*4bdc9457SAndroid Build Coastguard Worker uint32_t encode_regs_length_to_type(DRegisterList regs) {
71*4bdc9457SAndroid Build Coastguard Worker   switch (regs.length) {
72*4bdc9457SAndroid Build Coastguard Worker     case 1:
73*4bdc9457SAndroid Build Coastguard Worker       return 0x7;
74*4bdc9457SAndroid Build Coastguard Worker     case 2:
75*4bdc9457SAndroid Build Coastguard Worker       return 0xA;
76*4bdc9457SAndroid Build Coastguard Worker     case 3:
77*4bdc9457SAndroid Build Coastguard Worker       return 0x6;
78*4bdc9457SAndroid Build Coastguard Worker     case 4:
79*4bdc9457SAndroid Build Coastguard Worker       return 0x2;
80*4bdc9457SAndroid Build Coastguard Worker   }
81*4bdc9457SAndroid Build Coastguard Worker   return 0;
82*4bdc9457SAndroid Build Coastguard Worker }
83*4bdc9457SAndroid Build Coastguard Worker 
add(CoreRegister rd,CoreRegister rn,CoreRegister rm)84*4bdc9457SAndroid Build Coastguard Worker void Assembler::add(CoreRegister rd, CoreRegister rn, CoreRegister rm) {
85*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x8 << 20 | rn.code << 16 | rd.code << 12 | rm.code);
86*4bdc9457SAndroid Build Coastguard Worker }
87*4bdc9457SAndroid Build Coastguard Worker 
add(CoreRegister rd,CoreRegister rn,uint8_t imm)88*4bdc9457SAndroid Build Coastguard Worker void Assembler::add(CoreRegister rd, CoreRegister rn, uint8_t imm) {
89*4bdc9457SAndroid Build Coastguard Worker   // Rotation = 0, since imm is limited to 8 bits and fits in encoding.
90*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x28 << 20 | rn.code << 16 | rd.code << 12 | imm);
91*4bdc9457SAndroid Build Coastguard Worker }
92*4bdc9457SAndroid Build Coastguard Worker 
adds(CoreRegister rd,CoreRegister rn,uint8_t imm)93*4bdc9457SAndroid Build Coastguard Worker void Assembler::adds(CoreRegister rd, CoreRegister rn, uint8_t imm) {
94*4bdc9457SAndroid Build Coastguard Worker   // Rotation = 0, since imm is limited to 8 bits and fits in encoding.
95*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x29 << 20 | rn.code << 16 | rd.code << 12 | imm);
96*4bdc9457SAndroid Build Coastguard Worker }
97*4bdc9457SAndroid Build Coastguard Worker 
and_(CoreRegister rd,CoreRegister rn,uint8_t imm)98*4bdc9457SAndroid Build Coastguard Worker void Assembler::and_(CoreRegister rd, CoreRegister rn, uint8_t imm) {
99*4bdc9457SAndroid Build Coastguard Worker   // Rotation = 0, since imm is limited to 8 bits and fits in encoding.
100*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 1 << 25 | rn.code << 16 | rd.code << 12 | imm);
101*4bdc9457SAndroid Build Coastguard Worker }
102*4bdc9457SAndroid Build Coastguard Worker 
b(Condition c,Label & l)103*4bdc9457SAndroid Build Coastguard Worker void Assembler::b(Condition c, Label& l) {
104*4bdc9457SAndroid Build Coastguard Worker   if (l.bound) {
105*4bdc9457SAndroid Build Coastguard Worker     // Offset is relative to after this b instruction + kPCDelta.
106*4bdc9457SAndroid Build Coastguard Worker     const ptrdiff_t offset = l.offset - cursor_ - kPCDelta;
107*4bdc9457SAndroid Build Coastguard Worker     if (!branch_offset_valid(offset)) {
108*4bdc9457SAndroid Build Coastguard Worker       error_ = Error::kLabelOffsetOutOfBounds;
109*4bdc9457SAndroid Build Coastguard Worker       return;
110*4bdc9457SAndroid Build Coastguard Worker     }
111*4bdc9457SAndroid Build Coastguard Worker 
112*4bdc9457SAndroid Build Coastguard Worker     // No need to shift by 2 since our offset is already in terms of uint32_t.
113*4bdc9457SAndroid Build Coastguard Worker     emit32(c | 0xA << 24 | ((offset >> kInstructionSizeInBytesLog2) & 0x00FFFFFF));
114*4bdc9457SAndroid Build Coastguard Worker   } else {
115*4bdc9457SAndroid Build Coastguard Worker     if (!l.add_use(cursor_)) {
116*4bdc9457SAndroid Build Coastguard Worker       error_ = Error::kLabelHasTooManyUsers;
117*4bdc9457SAndroid Build Coastguard Worker       return;
118*4bdc9457SAndroid Build Coastguard Worker     }
119*4bdc9457SAndroid Build Coastguard Worker     // Emit 0 offset first, will patch it up when label is bound later.
120*4bdc9457SAndroid Build Coastguard Worker     emit32(c | 0xA << 24);
121*4bdc9457SAndroid Build Coastguard Worker   }
122*4bdc9457SAndroid Build Coastguard Worker }
123*4bdc9457SAndroid Build Coastguard Worker 
bind(Label & l)124*4bdc9457SAndroid Build Coastguard Worker void Assembler::bind(Label& l) {
125*4bdc9457SAndroid Build Coastguard Worker   if (error_ != Error::kNoError) {
126*4bdc9457SAndroid Build Coastguard Worker     return;
127*4bdc9457SAndroid Build Coastguard Worker   }
128*4bdc9457SAndroid Build Coastguard Worker 
129*4bdc9457SAndroid Build Coastguard Worker   if (l.bound) {
130*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kLabelAlreadyBound;
131*4bdc9457SAndroid Build Coastguard Worker     return;
132*4bdc9457SAndroid Build Coastguard Worker   }
133*4bdc9457SAndroid Build Coastguard Worker 
134*4bdc9457SAndroid Build Coastguard Worker   l.bound = true;
135*4bdc9457SAndroid Build Coastguard Worker   l.offset = cursor_;
136*4bdc9457SAndroid Build Coastguard Worker 
137*4bdc9457SAndroid Build Coastguard Worker   // Patch all users.
138*4bdc9457SAndroid Build Coastguard Worker   for (size_t i = 0; i < l.num_users; i++) {
139*4bdc9457SAndroid Build Coastguard Worker     byte* user = l.users[i];
140*4bdc9457SAndroid Build Coastguard Worker     const ptrdiff_t offset = l.offset - user - kPCDelta;
141*4bdc9457SAndroid Build Coastguard Worker     uint32_t* instr = reinterpret_cast<uint32_t*>(user);
142*4bdc9457SAndroid Build Coastguard Worker 
143*4bdc9457SAndroid Build Coastguard Worker     if (!branch_offset_valid(offset)) {
144*4bdc9457SAndroid Build Coastguard Worker       error_ = Error::kLabelOffsetOutOfBounds;
145*4bdc9457SAndroid Build Coastguard Worker       return;
146*4bdc9457SAndroid Build Coastguard Worker     }
147*4bdc9457SAndroid Build Coastguard Worker 
148*4bdc9457SAndroid Build Coastguard Worker     *instr |= (offset >> kInstructionSizeInBytesLog2) & 0x00FFFFFF;
149*4bdc9457SAndroid Build Coastguard Worker   }
150*4bdc9457SAndroid Build Coastguard Worker }
151*4bdc9457SAndroid Build Coastguard Worker 
bic(CoreRegister rd,CoreRegister rn,uint8_t imm)152*4bdc9457SAndroid Build Coastguard Worker void Assembler::bic(CoreRegister rd, CoreRegister rn, uint8_t imm) {
153*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x03C00000 | rn.code << 16 | rd.code << 12 | imm);
154*4bdc9457SAndroid Build Coastguard Worker }
155*4bdc9457SAndroid Build Coastguard Worker 
bx(CoreRegister rm)156*4bdc9457SAndroid Build Coastguard Worker void Assembler::bx(CoreRegister rm) {
157*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x12fff10 | rm.code);
158*4bdc9457SAndroid Build Coastguard Worker }
159*4bdc9457SAndroid Build Coastguard Worker 
cmp(CoreRegister rn,uint8_t imm)160*4bdc9457SAndroid Build Coastguard Worker void Assembler::cmp(CoreRegister rn, uint8_t imm) {
161*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x35 << 20 | rn.code << 16 | imm);
162*4bdc9457SAndroid Build Coastguard Worker }
163*4bdc9457SAndroid Build Coastguard Worker 
cmp(CoreRegister rn,CoreRegister rm)164*4bdc9457SAndroid Build Coastguard Worker void Assembler::cmp(CoreRegister rn, CoreRegister rm) {
165*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x01500000 | rn.code << 16 | rm.code);
166*4bdc9457SAndroid Build Coastguard Worker }
167*4bdc9457SAndroid Build Coastguard Worker 
ldr(CoreRegister rt,MemOperand op,int32_t offset)168*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(CoreRegister rt, MemOperand op, int32_t offset) {
169*4bdc9457SAndroid Build Coastguard Worker   ldr(rt, MemOperand(op.base(), offset, AddressingMode::kPostIndexed));
170*4bdc9457SAndroid Build Coastguard Worker }
171*4bdc9457SAndroid Build Coastguard Worker 
ldr(CoreRegister rt,MemOperand op)172*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(CoreRegister rt, MemOperand op) {
173*4bdc9457SAndroid Build Coastguard Worker   const int32_t offset = op.offset();
174*4bdc9457SAndroid Build Coastguard Worker   if (std::abs(offset) > kUint12Max) {
175*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
176*4bdc9457SAndroid Build Coastguard Worker     return;
177*4bdc9457SAndroid Build Coastguard Worker   }
178*4bdc9457SAndroid Build Coastguard Worker 
179*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x41 << 20 | encode_mem_puw(op) | rt.code << 12 | offset);
180*4bdc9457SAndroid Build Coastguard Worker }
181*4bdc9457SAndroid Build Coastguard Worker 
ldrd(CoreRegister rt,CoreRegister rt2,MemOperand op)182*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldrd(CoreRegister rt, CoreRegister rt2, MemOperand op) {
183*4bdc9457SAndroid Build Coastguard Worker   const int32_t offset = op.offset();
184*4bdc9457SAndroid Build Coastguard Worker   if ((std::abs(op.offset()) > UINT8_MAX) || (rt.code + 1 != rt2.code)) {
185*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
186*4bdc9457SAndroid Build Coastguard Worker     return;
187*4bdc9457SAndroid Build Coastguard Worker   }
188*4bdc9457SAndroid Build Coastguard Worker   const uint32_t offset_top = (offset & 0xF0) << 4;
189*4bdc9457SAndroid Build Coastguard Worker   const uint32_t offset_bot = (offset & 0xF);
190*4bdc9457SAndroid Build Coastguard Worker 
191*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x004000D0 | encode_mem_puw(op) | rt.code << 12 | offset_top | offset_bot);
192*4bdc9457SAndroid Build Coastguard Worker }
193*4bdc9457SAndroid Build Coastguard Worker 
mov(CoreRegister rd,CoreRegister rm)194*4bdc9457SAndroid Build Coastguard Worker void Assembler::mov(CoreRegister rd, CoreRegister rm) {
195*4bdc9457SAndroid Build Coastguard Worker   mov(kAL, rd, rm);
196*4bdc9457SAndroid Build Coastguard Worker }
197*4bdc9457SAndroid Build Coastguard Worker 
mov(Condition c,CoreRegister Rd,CoreRegister Rm)198*4bdc9457SAndroid Build Coastguard Worker void Assembler::mov(Condition c, CoreRegister Rd, CoreRegister Rm) {
199*4bdc9457SAndroid Build Coastguard Worker   emit32(c | 0x1A << 20 | Rd.code << 12 | Rm.code);
200*4bdc9457SAndroid Build Coastguard Worker }
201*4bdc9457SAndroid Build Coastguard Worker 
nop()202*4bdc9457SAndroid Build Coastguard Worker void Assembler::nop() {
203*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0320F000);
204*4bdc9457SAndroid Build Coastguard Worker }
205*4bdc9457SAndroid Build Coastguard Worker 
pld(MemOperand op)206*4bdc9457SAndroid Build Coastguard Worker void Assembler::pld(MemOperand op) {
207*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF550F000 | op.u() << 23 | op.base().code << 16 | op.offset());
208*4bdc9457SAndroid Build Coastguard Worker }
209*4bdc9457SAndroid Build Coastguard Worker 
pop(CoreRegisterList regs)210*4bdc9457SAndroid Build Coastguard Worker void Assembler::pop(CoreRegisterList regs) {
211*4bdc9457SAndroid Build Coastguard Worker   if (!regs.has_more_than_one_register()) {
212*4bdc9457SAndroid Build Coastguard Worker     // TODO(zhin): there is a different valid encoding for single register.
213*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
214*4bdc9457SAndroid Build Coastguard Worker     return;
215*4bdc9457SAndroid Build Coastguard Worker   }
216*4bdc9457SAndroid Build Coastguard Worker 
217*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x8BD << 16 | regs.list);
218*4bdc9457SAndroid Build Coastguard Worker }
219*4bdc9457SAndroid Build Coastguard Worker 
push(CoreRegisterList regs)220*4bdc9457SAndroid Build Coastguard Worker void Assembler::push(CoreRegisterList regs) {
221*4bdc9457SAndroid Build Coastguard Worker   if (!regs.has_more_than_one_register()) {
222*4bdc9457SAndroid Build Coastguard Worker     // TODO(zhin): there is a different valid encoding for single register.
223*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
224*4bdc9457SAndroid Build Coastguard Worker     return;
225*4bdc9457SAndroid Build Coastguard Worker   }
226*4bdc9457SAndroid Build Coastguard Worker 
227*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x92D << 16 | regs.list);
228*4bdc9457SAndroid Build Coastguard Worker }
229*4bdc9457SAndroid Build Coastguard Worker 
str(CoreRegister rt,MemOperand op)230*4bdc9457SAndroid Build Coastguard Worker void Assembler::str(CoreRegister rt, MemOperand op) {
231*4bdc9457SAndroid Build Coastguard Worker   const int32_t offset = op.offset();
232*4bdc9457SAndroid Build Coastguard Worker   if (std::abs(offset) > kUint12Max) {
233*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
234*4bdc9457SAndroid Build Coastguard Worker     return;
235*4bdc9457SAndroid Build Coastguard Worker   }
236*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 1 << 26 | encode_mem_puw(op) | rt.code << 12 | offset);
237*4bdc9457SAndroid Build Coastguard Worker }
238*4bdc9457SAndroid Build Coastguard Worker 
sub(CoreRegister rd,CoreRegister rn,uint8_t imm)239*4bdc9457SAndroid Build Coastguard Worker void Assembler::sub(CoreRegister rd, CoreRegister rn, uint8_t imm) {
240*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x24 << 20 | rn.code << 16 | rd.code << 12 | imm);
241*4bdc9457SAndroid Build Coastguard Worker }
242*4bdc9457SAndroid Build Coastguard Worker 
sub(CoreRegister rd,CoreRegister rn,CoreRegister rm)243*4bdc9457SAndroid Build Coastguard Worker void Assembler::sub(CoreRegister rd, CoreRegister rn, CoreRegister rm) {
244*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x4 << 20 | rn.code << 16 | rd.code << 12 | rm.code);
245*4bdc9457SAndroid Build Coastguard Worker }
246*4bdc9457SAndroid Build Coastguard Worker 
subs(CoreRegister rd,CoreRegister rn,uint8_t imm)247*4bdc9457SAndroid Build Coastguard Worker void Assembler::subs(CoreRegister rd, CoreRegister rn, uint8_t imm) {
248*4bdc9457SAndroid Build Coastguard Worker   // Rotation = 0, since imm is limited to 8 bits and fits in encoding.
249*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x25 << 20 | rn.code << 16 | rd.code << 12 | imm);
250*4bdc9457SAndroid Build Coastguard Worker }
251*4bdc9457SAndroid Build Coastguard Worker 
tst(CoreRegister rn,uint8_t imm)252*4bdc9457SAndroid Build Coastguard Worker void Assembler::tst(CoreRegister rn, uint8_t imm) {
253*4bdc9457SAndroid Build Coastguard Worker   // Rotation = 0, since imm is limited to 8 bits and fits in encoding.
254*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x31 << 20 | rn.code << 16 | imm);
255*4bdc9457SAndroid Build Coastguard Worker }
256*4bdc9457SAndroid Build Coastguard Worker 
vabs_f32(QRegister qd,QRegister qm)257*4bdc9457SAndroid Build Coastguard Worker void Assembler::vabs_f32(QRegister qd, QRegister qm) {
258*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3B90740 | encode(qd, 22, 12) | encode(qm, 5, 0));
259*4bdc9457SAndroid Build Coastguard Worker }
260*4bdc9457SAndroid Build Coastguard Worker 
vadd_f32(QRegister qd,QRegister qn,QRegister qm)261*4bdc9457SAndroid Build Coastguard Worker void Assembler::vadd_f32(QRegister qd, QRegister qn, QRegister qm) {
262*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2000D40 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0));
263*4bdc9457SAndroid Build Coastguard Worker }
264*4bdc9457SAndroid Build Coastguard Worker 
vcmpe_f32(SRegister sd,SRegister sm)265*4bdc9457SAndroid Build Coastguard Worker void Assembler::vcmpe_f32(SRegister sd, SRegister sm) {
266*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0EB40AC0 | encode(sd, 22, 12) | encode(sm, 5, 0));
267*4bdc9457SAndroid Build Coastguard Worker }
268*4bdc9457SAndroid Build Coastguard Worker 
vcvt_f32_s32(QRegister qd,QRegister qm)269*4bdc9457SAndroid Build Coastguard Worker void Assembler::vcvt_f32_s32(QRegister qd, QRegister qm) {
270*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3BB0640 | encode(qd, 22, 12) | encode(qm, 5, 0));
271*4bdc9457SAndroid Build Coastguard Worker }
272*4bdc9457SAndroid Build Coastguard Worker 
vcvt_s32_f32(QRegister qd,QRegister qm)273*4bdc9457SAndroid Build Coastguard Worker void Assembler::vcvt_s32_f32(QRegister qd, QRegister qm) {
274*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3BB0740 | encode(qd, 22, 12) | encode(qm, 5, 0));
275*4bdc9457SAndroid Build Coastguard Worker }
276*4bdc9457SAndroid Build Coastguard Worker 
vcvtn_s32_f32(QRegister qd,QRegister qm)277*4bdc9457SAndroid Build Coastguard Worker void Assembler::vcvtn_s32_f32(QRegister qd, QRegister qm) {
278*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3BB0140 | encode(qd, 22, 12) | encode(qm, 5, 0));
279*4bdc9457SAndroid Build Coastguard Worker }
280*4bdc9457SAndroid Build Coastguard Worker 
vdup(DataSize size,QRegister qd,DRegisterLane dm)281*4bdc9457SAndroid Build Coastguard Worker void Assembler::vdup(DataSize size, QRegister qd, DRegisterLane dm) {
282*4bdc9457SAndroid Build Coastguard Worker   uint8_t imm4 = 0;
283*4bdc9457SAndroid Build Coastguard Worker   switch (size) {
284*4bdc9457SAndroid Build Coastguard Worker     case k8:
285*4bdc9457SAndroid Build Coastguard Worker       if (dm.lane > 7) {
286*4bdc9457SAndroid Build Coastguard Worker         error_ = Error::kInvalidLaneIndex;
287*4bdc9457SAndroid Build Coastguard Worker         return;
288*4bdc9457SAndroid Build Coastguard Worker       }
289*4bdc9457SAndroid Build Coastguard Worker       imm4 = 1 | ((dm.lane & 0x7) << 1);
290*4bdc9457SAndroid Build Coastguard Worker       break;
291*4bdc9457SAndroid Build Coastguard Worker     case k16:
292*4bdc9457SAndroid Build Coastguard Worker       if (dm.lane > 3) {
293*4bdc9457SAndroid Build Coastguard Worker         error_ = Error::kInvalidLaneIndex;
294*4bdc9457SAndroid Build Coastguard Worker         return;
295*4bdc9457SAndroid Build Coastguard Worker       }
296*4bdc9457SAndroid Build Coastguard Worker       imm4 = 2 | ((dm.lane & 0x3) << 2);
297*4bdc9457SAndroid Build Coastguard Worker       break;
298*4bdc9457SAndroid Build Coastguard Worker     case k32:
299*4bdc9457SAndroid Build Coastguard Worker       if (dm.lane > 1) {
300*4bdc9457SAndroid Build Coastguard Worker         error_ = Error::kInvalidLaneIndex;
301*4bdc9457SAndroid Build Coastguard Worker         return;
302*4bdc9457SAndroid Build Coastguard Worker       }
303*4bdc9457SAndroid Build Coastguard Worker       imm4 = 4 | ((dm.lane & 0x1) << 3);
304*4bdc9457SAndroid Build Coastguard Worker       break;
305*4bdc9457SAndroid Build Coastguard Worker   }
306*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3B00C40 | imm4 << 16 | encode(qd, 22, 12) | encode(dm, 5, 0));
307*4bdc9457SAndroid Build Coastguard Worker }
308*4bdc9457SAndroid Build Coastguard Worker 
vext_8(QRegister qd,QRegister qn,QRegister qm,uint8_t imm4)309*4bdc9457SAndroid Build Coastguard Worker void Assembler::vext_8(QRegister qd, QRegister qn, QRegister qm, uint8_t imm4) {
310*4bdc9457SAndroid Build Coastguard Worker   if (imm4 > 15) {
311*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
312*4bdc9457SAndroid Build Coastguard Worker     return;
313*4bdc9457SAndroid Build Coastguard Worker   }
314*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2B00040 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0) | imm4 << 8);
315*4bdc9457SAndroid Build Coastguard Worker }
316*4bdc9457SAndroid Build Coastguard Worker 
vld1(DataSize size,DRegisterList regs,MemOperand op)317*4bdc9457SAndroid Build Coastguard Worker void Assembler::vld1(DataSize size, DRegisterList regs, MemOperand op) {
318*4bdc9457SAndroid Build Coastguard Worker   const uint8_t rm = op.mode() == AddressingMode::kPostIndexed ? 0xD : 0xF;
319*4bdc9457SAndroid Build Coastguard Worker   vld1(size, regs, op, CoreRegister{rm});
320*4bdc9457SAndroid Build Coastguard Worker }
321*4bdc9457SAndroid Build Coastguard Worker 
vld1(DataSize size,DRegisterList regs,MemOperand op,CoreRegister rm)322*4bdc9457SAndroid Build Coastguard Worker void Assembler::vld1(DataSize size, DRegisterList regs, MemOperand op, CoreRegister rm) {
323*4bdc9457SAndroid Build Coastguard Worker   const uint8_t type = encode_regs_length_to_type(regs);
324*4bdc9457SAndroid Build Coastguard Worker   if (!type) {
325*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
326*4bdc9457SAndroid Build Coastguard Worker     return;
327*4bdc9457SAndroid Build Coastguard Worker   }
328*4bdc9457SAndroid Build Coastguard Worker 
329*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF4200000 | encode(regs.start, 22, 12) | op.base().code << 16 | type << 8 | size << 6 | rm.code);
330*4bdc9457SAndroid Build Coastguard Worker }
331*4bdc9457SAndroid Build Coastguard Worker 
vld1_32(DRegisterLane dd,MemOperand op)332*4bdc9457SAndroid Build Coastguard Worker void Assembler::vld1_32(DRegisterLane dd, MemOperand op) {
333*4bdc9457SAndroid Build Coastguard Worker   if (dd.lane > 1) {
334*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidLaneIndex;
335*4bdc9457SAndroid Build Coastguard Worker     return;
336*4bdc9457SAndroid Build Coastguard Worker   }
337*4bdc9457SAndroid Build Coastguard Worker   const uint32_t rm = op.mode() == AddressingMode::kPostIndexed ? 0xD : 0xF;
338*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0xF4A00800 | dd.lane << 7 | encode(dd, 22, 12) | op.base().code << 16 | rm);
339*4bdc9457SAndroid Build Coastguard Worker }
340*4bdc9457SAndroid Build Coastguard Worker 
vld1r_32(DRegisterList regs,MemOperand op)341*4bdc9457SAndroid Build Coastguard Worker void Assembler::vld1r_32(DRegisterList regs, MemOperand op) {
342*4bdc9457SAndroid Build Coastguard Worker   if ((op.mode() == AddressingMode::kOffset && op.offset() != 0) || regs.length > 2) {
343*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
344*4bdc9457SAndroid Build Coastguard Worker     return;
345*4bdc9457SAndroid Build Coastguard Worker   }
346*4bdc9457SAndroid Build Coastguard Worker 
347*4bdc9457SAndroid Build Coastguard Worker   const uint32_t rm = op.mode() == AddressingMode::kPostIndexed ? 0xD : 0xF;
348*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF4A00C80 | encode(regs.start, 22, 12) | op.base().code << 16 | (regs.length - 1) << 5 | rm);
349*4bdc9457SAndroid Build Coastguard Worker }
350*4bdc9457SAndroid Build Coastguard Worker 
vld2r_32(VLoadStoreRegList regs,MemOperand op)351*4bdc9457SAndroid Build Coastguard Worker void Assembler::vld2r_32(VLoadStoreRegList regs, MemOperand op) {
352*4bdc9457SAndroid Build Coastguard Worker   if ((op.mode() == AddressingMode::kOffset && op.offset() != 0)) {
353*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
354*4bdc9457SAndroid Build Coastguard Worker     return;
355*4bdc9457SAndroid Build Coastguard Worker   }
356*4bdc9457SAndroid Build Coastguard Worker   uint8_t spacing = regs.double_spaced ? 2 : 1;
357*4bdc9457SAndroid Build Coastguard Worker   if (regs.reg1.code != regs.reg2.code - spacing) {
358*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
359*4bdc9457SAndroid Build Coastguard Worker     return;
360*4bdc9457SAndroid Build Coastguard Worker   }
361*4bdc9457SAndroid Build Coastguard Worker 
362*4bdc9457SAndroid Build Coastguard Worker   size_t t = spacing - 1;
363*4bdc9457SAndroid Build Coastguard Worker   const uint32_t rm = op.mode() == AddressingMode::kPostIndexed ? op.base().code : 0xF;
364*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF4A00D80 | encode(regs.reg1, 22, 12) | op.base().code << 16 | t << 5 | rm);
365*4bdc9457SAndroid Build Coastguard Worker }
366*4bdc9457SAndroid Build Coastguard Worker 
367*4bdc9457SAndroid Build Coastguard Worker 
vld3r_32(VLoadStoreRegList regs,MemOperand op)368*4bdc9457SAndroid Build Coastguard Worker void Assembler::vld3r_32(VLoadStoreRegList regs, MemOperand op) {
369*4bdc9457SAndroid Build Coastguard Worker   if ((op.mode() == AddressingMode::kOffset && op.offset() != 0)) {
370*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
371*4bdc9457SAndroid Build Coastguard Worker     return;
372*4bdc9457SAndroid Build Coastguard Worker   }
373*4bdc9457SAndroid Build Coastguard Worker   uint8_t spacing = regs.double_spaced ? 2 : 1;
374*4bdc9457SAndroid Build Coastguard Worker   if (regs.reg1.code != regs.reg2.code - spacing || regs.reg2.code != regs.reg3.code - spacing) {
375*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
376*4bdc9457SAndroid Build Coastguard Worker     return;
377*4bdc9457SAndroid Build Coastguard Worker   }
378*4bdc9457SAndroid Build Coastguard Worker 
379*4bdc9457SAndroid Build Coastguard Worker   size_t t = spacing - 1;
380*4bdc9457SAndroid Build Coastguard Worker   const uint32_t rm = op.mode() == AddressingMode::kPostIndexed ? op.base().code : 0xF;
381*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF4A00E80 | encode(regs.reg1, 22, 12) | op.base().code << 16 | t << 5 | rm);
382*4bdc9457SAndroid Build Coastguard Worker }
383*4bdc9457SAndroid Build Coastguard Worker 
vldm(MemOperand rn,SRegisterList regs)384*4bdc9457SAndroid Build Coastguard Worker void Assembler::vldm(MemOperand rn, SRegisterList regs) {
385*4bdc9457SAndroid Build Coastguard Worker   if (invalid_register_list(regs)) {
386*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
387*4bdc9457SAndroid Build Coastguard Worker     return;
388*4bdc9457SAndroid Build Coastguard Worker   }
389*4bdc9457SAndroid Build Coastguard Worker   uint32_t w = (rn.mode() == AddressingMode::kOffset ? 0 : 1) << 21;
390*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0C900A00 | w | rn.base().code << 16 | encode(regs, 22, 12));
391*4bdc9457SAndroid Build Coastguard Worker }
392*4bdc9457SAndroid Build Coastguard Worker 
vldm(MemOperand rn,DRegisterList regs)393*4bdc9457SAndroid Build Coastguard Worker void Assembler::vldm(MemOperand rn, DRegisterList regs) {
394*4bdc9457SAndroid Build Coastguard Worker   if (invalid_register_list(regs)) {
395*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
396*4bdc9457SAndroid Build Coastguard Worker     return;
397*4bdc9457SAndroid Build Coastguard Worker   }
398*4bdc9457SAndroid Build Coastguard Worker   uint32_t w = (rn.mode() == AddressingMode::kOffset ? 0 : 1) << 21;
399*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0C900B00 | w | rn.base().code << 16 | encode(regs, 22, 12));
400*4bdc9457SAndroid Build Coastguard Worker }
401*4bdc9457SAndroid Build Coastguard Worker 
vldr(SRegister sd,MemOperand op)402*4bdc9457SAndroid Build Coastguard Worker void Assembler::vldr(SRegister sd, MemOperand op) {
403*4bdc9457SAndroid Build Coastguard Worker   const uint32_t offset = std::abs(op.offset());
404*4bdc9457SAndroid Build Coastguard Worker   if (op.mode() != AddressingMode::kOffset || offset > kUint10Max || offset % 4 != 0) {
405*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
406*4bdc9457SAndroid Build Coastguard Worker     return;
407*4bdc9457SAndroid Build Coastguard Worker   }
408*4bdc9457SAndroid Build Coastguard Worker 
409*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0D100A00 | op.u() << 23 | encode(sd, 22, 12) | op.base().code << 16 | offset >> 2);
410*4bdc9457SAndroid Build Coastguard Worker }
411*4bdc9457SAndroid Build Coastguard Worker 
vldr(DRegister dd,MemOperand op)412*4bdc9457SAndroid Build Coastguard Worker void Assembler::vldr(DRegister dd, MemOperand op) {
413*4bdc9457SAndroid Build Coastguard Worker   const uint32_t offset = std::abs(op.offset());
414*4bdc9457SAndroid Build Coastguard Worker   if (op.mode() != AddressingMode::kOffset || offset > kUint10Max || offset % 4 != 0) {
415*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
416*4bdc9457SAndroid Build Coastguard Worker     return;
417*4bdc9457SAndroid Build Coastguard Worker   }
418*4bdc9457SAndroid Build Coastguard Worker 
419*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0D100B00 | op.u() << 23 | encode(dd, 22, 12) | op.base().code << 16 | offset >> 2);
420*4bdc9457SAndroid Build Coastguard Worker }
421*4bdc9457SAndroid Build Coastguard Worker 
vmax_f32(QRegister qd,QRegister qn,QRegister qm)422*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmax_f32(QRegister qd, QRegister qn, QRegister qm) {
423*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2000F40 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0));
424*4bdc9457SAndroid Build Coastguard Worker }
425*4bdc9457SAndroid Build Coastguard Worker 
vmax_s8(QRegister qd,QRegister qn,QRegister qm)426*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmax_s8(QRegister qd, QRegister qn, QRegister qm) {
427*4bdc9457SAndroid Build Coastguard Worker  emit32(0xF2000640 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0));
428*4bdc9457SAndroid Build Coastguard Worker }
429*4bdc9457SAndroid Build Coastguard Worker 
vmin_f32(QRegister qd,QRegister qn,QRegister qm)430*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmin_f32(QRegister qd, QRegister qn, QRegister qm) {
431*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2200F40 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0));
432*4bdc9457SAndroid Build Coastguard Worker }
433*4bdc9457SAndroid Build Coastguard Worker 
vmin_s8(QRegister qd,QRegister qn,QRegister qm)434*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmin_s8(QRegister qd, QRegister qn, QRegister qm) {
435*4bdc9457SAndroid Build Coastguard Worker  emit32(0xF2000650 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0));
436*4bdc9457SAndroid Build Coastguard Worker }
437*4bdc9457SAndroid Build Coastguard Worker 
vmla_f32(SRegister sd,SRegister sn,SRegister sm)438*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmla_f32(SRegister sd, SRegister sn, SRegister sm) {
439*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0E000A00 | encode(sd, 22, 12) | encode (sn, 7, 16) | encode(sm, 5, 0));
440*4bdc9457SAndroid Build Coastguard Worker }
441*4bdc9457SAndroid Build Coastguard Worker 
vmla_f32(QRegister qd,QRegister qn,DRegisterLane dm)442*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmla_f32(QRegister qd, QRegister qn, DRegisterLane dm) {
443*4bdc9457SAndroid Build Coastguard Worker   if (dm.lane > 1) {
444*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidLaneIndex;
445*4bdc9457SAndroid Build Coastguard Worker     return;
446*4bdc9457SAndroid Build Coastguard Worker   }
447*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3A00140 | encode(qd, 22, 12) | encode(qn, 7, 16) | dm.lane << 5 | dm.code);
448*4bdc9457SAndroid Build Coastguard Worker }
449*4bdc9457SAndroid Build Coastguard Worker 
vmlal_s16(QRegister qd,DRegister dn,DRegisterLane dm)450*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmlal_s16(QRegister qd, DRegister dn, DRegisterLane dm) {
451*4bdc9457SAndroid Build Coastguard Worker   if (dm.lane > 3) {
452*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidLaneIndex;
453*4bdc9457SAndroid Build Coastguard Worker     return;
454*4bdc9457SAndroid Build Coastguard Worker   }
455*4bdc9457SAndroid Build Coastguard Worker   if (dm.code > 7) {
456*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
457*4bdc9457SAndroid Build Coastguard Worker     return;
458*4bdc9457SAndroid Build Coastguard Worker   }
459*4bdc9457SAndroid Build Coastguard Worker 
460*4bdc9457SAndroid Build Coastguard Worker   uint8_t lane_top = dm.lane >> 1;
461*4bdc9457SAndroid Build Coastguard Worker   uint8_t lane_bot = dm.lane & 1;
462*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2900240 | encode(qd, 22, 12) | encode(dn, 7, 16) | lane_top << 5 | lane_bot << 3 | dm.code);
463*4bdc9457SAndroid Build Coastguard Worker }
464*4bdc9457SAndroid Build Coastguard Worker 
vmov(QRegister qd,uint8_t imm)465*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmov(QRegister qd, uint8_t imm) {
466*4bdc9457SAndroid Build Coastguard Worker   if (imm != 0) {
467*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
468*4bdc9457SAndroid Build Coastguard Worker     return;
469*4bdc9457SAndroid Build Coastguard Worker   }
470*4bdc9457SAndroid Build Coastguard Worker 
471*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2800050 | encode(qd, 22, 12));
472*4bdc9457SAndroid Build Coastguard Worker }
473*4bdc9457SAndroid Build Coastguard Worker 
vmov(SRegister sd,SRegister sm)474*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmov(SRegister sd, SRegister sm) {
475*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0EB00A40 | encode(sd, 22, 12) | encode(sm, 5, 0));
476*4bdc9457SAndroid Build Coastguard Worker }
477*4bdc9457SAndroid Build Coastguard Worker 
vmov(DRegister dm,CoreRegister rt,CoreRegister rt2)478*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmov(DRegister dm, CoreRegister rt, CoreRegister rt2) {
479*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0C400B10 | rt2.code << 16 | rt.code << 12 | encode(dm, 5, 0));
480*4bdc9457SAndroid Build Coastguard Worker }
481*4bdc9457SAndroid Build Coastguard Worker 
vmov(DRegister dd,DRegister dm)482*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmov(DRegister dd, DRegister dm) {
483*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2200110 | encode(dd, 22, 12) | encode(dm, 7, 16) | encode(dm, 5, 0));
484*4bdc9457SAndroid Build Coastguard Worker }
485*4bdc9457SAndroid Build Coastguard Worker 
vmov(QRegister qd,QRegister qm)486*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmov(QRegister qd, QRegister qm) {
487*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2200150 | encode(qd, 22, 12) | encode(qm, 7, 16) | encode(qm, 5, 0));
488*4bdc9457SAndroid Build Coastguard Worker }
489*4bdc9457SAndroid Build Coastguard Worker 
vmov_f32(Condition c,SRegister sd,SRegister sm)490*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmov_f32(Condition c, SRegister sd, SRegister sm) {
491*4bdc9457SAndroid Build Coastguard Worker   emit32(c | 0x0EB00A40 | encode(sd, 22, 12) | encode(sm, 5, 0));
492*4bdc9457SAndroid Build Coastguard Worker }
493*4bdc9457SAndroid Build Coastguard Worker 
vmov_f64(DRegister dd,DRegister dm)494*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmov_f64(DRegister dd, DRegister dm) {
495*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0EB00B40 | encode(dd, 22, 12) | encode(dm, 5, 0));
496*4bdc9457SAndroid Build Coastguard Worker }
497*4bdc9457SAndroid Build Coastguard Worker 
vmovl_s8(QRegister qd,DRegister dm)498*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmovl_s8(QRegister qd, DRegister dm) {
499*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2880A10 | encode(qd, 22, 12) | encode(dm, 5, 0));
500*4bdc9457SAndroid Build Coastguard Worker }
501*4bdc9457SAndroid Build Coastguard Worker 
vmrs(CoreRegister rt,SpecialFPRegister spec_reg)502*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmrs(CoreRegister rt, SpecialFPRegister spec_reg) {
503*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0EF00A10 | static_cast<uint32_t>(spec_reg) << 16 | rt.code << 12);
504*4bdc9457SAndroid Build Coastguard Worker }
505*4bdc9457SAndroid Build Coastguard Worker 
vmul_f32(QRegister qd,QRegister qn,QRegister qm)506*4bdc9457SAndroid Build Coastguard Worker void Assembler::vmul_f32(QRegister qd, QRegister qn, QRegister qm) {
507*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3000D50 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0));
508*4bdc9457SAndroid Build Coastguard Worker }
509*4bdc9457SAndroid Build Coastguard Worker 
vneg_f32(QRegister qd,QRegister qm)510*4bdc9457SAndroid Build Coastguard Worker void Assembler::vneg_f32(QRegister qd, QRegister qm) {
511*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3B907C0 | encode(qd, 22, 12) | encode(qm, 5, 0));
512*4bdc9457SAndroid Build Coastguard Worker }
513*4bdc9457SAndroid Build Coastguard Worker 
vpop(DRegisterList regs)514*4bdc9457SAndroid Build Coastguard Worker void Assembler::vpop(DRegisterList regs) {
515*4bdc9457SAndroid Build Coastguard Worker   if (invalid_register_list(regs)) {
516*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
517*4bdc9457SAndroid Build Coastguard Worker     return;
518*4bdc9457SAndroid Build Coastguard Worker   }
519*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | encode(regs, 22, 12) | 0xCBD << 16 | 0xB << 8);
520*4bdc9457SAndroid Build Coastguard Worker }
521*4bdc9457SAndroid Build Coastguard Worker 
vpush(DRegisterList regs)522*4bdc9457SAndroid Build Coastguard Worker void Assembler::vpush(DRegisterList regs) {
523*4bdc9457SAndroid Build Coastguard Worker   if (invalid_register_list(regs)) {
524*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
525*4bdc9457SAndroid Build Coastguard Worker     return;
526*4bdc9457SAndroid Build Coastguard Worker   }
527*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | encode(regs, 22, 12) | 0xD2D << 16 | 0xB << 8);
528*4bdc9457SAndroid Build Coastguard Worker }
529*4bdc9457SAndroid Build Coastguard Worker 
vpush(SRegisterList regs)530*4bdc9457SAndroid Build Coastguard Worker void Assembler::vpush(SRegisterList regs) {
531*4bdc9457SAndroid Build Coastguard Worker   if (invalid_register_list(regs)) {
532*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
533*4bdc9457SAndroid Build Coastguard Worker     return;
534*4bdc9457SAndroid Build Coastguard Worker   }
535*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | encode(regs, 22, 12) | 0xD2D << 16 | 0xA << 8);
536*4bdc9457SAndroid Build Coastguard Worker }
537*4bdc9457SAndroid Build Coastguard Worker 
vqadd_s16(QRegister qd,QRegister qn,QRegister qm)538*4bdc9457SAndroid Build Coastguard Worker void Assembler::vqadd_s16(QRegister qd, QRegister qn, QRegister qm) {
539*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2100050 | encode(qd, 22, 12) | encode(qn, 7, 16) | encode(qm, 5, 0));
540*4bdc9457SAndroid Build Coastguard Worker }
541*4bdc9457SAndroid Build Coastguard Worker 
vqdmulh_s32(QRegister qd,QRegister qn,DRegisterLane dm)542*4bdc9457SAndroid Build Coastguard Worker void Assembler::vqdmulh_s32(QRegister qd, QRegister qn, DRegisterLane dm) {
543*4bdc9457SAndroid Build Coastguard Worker   if (dm.code > 15) {
544*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
545*4bdc9457SAndroid Build Coastguard Worker     return;
546*4bdc9457SAndroid Build Coastguard Worker   }
547*4bdc9457SAndroid Build Coastguard Worker   if (dm.lane > 1) {
548*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidLaneIndex;
549*4bdc9457SAndroid Build Coastguard Worker     return;
550*4bdc9457SAndroid Build Coastguard Worker   }
551*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3A00C40 | encode(qd, 22, 12) | encode(qn, 7, 16) | dm.lane << 5 | dm.code);
552*4bdc9457SAndroid Build Coastguard Worker }
553*4bdc9457SAndroid Build Coastguard Worker 
vqmovn_s16(DRegister dd,QRegister qm)554*4bdc9457SAndroid Build Coastguard Worker void Assembler::vqmovn_s16(DRegister dd, QRegister qm) {
555*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3B20280 | encode(dd, 22, 12) | encode(qm, 5, 0));
556*4bdc9457SAndroid Build Coastguard Worker }
557*4bdc9457SAndroid Build Coastguard Worker 
vqmovn_s32(DRegister dd,QRegister qm)558*4bdc9457SAndroid Build Coastguard Worker void Assembler::vqmovn_s32(DRegister dd, QRegister qm) {
559*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF3B60280 | encode(dd, 22, 12) | encode(qm, 5, 0));
560*4bdc9457SAndroid Build Coastguard Worker }
561*4bdc9457SAndroid Build Coastguard Worker 
vqshl_s32(QRegister qd,QRegister qm,QRegister qn)562*4bdc9457SAndroid Build Coastguard Worker void Assembler::vqshl_s32(QRegister qd, QRegister qm, QRegister qn) {
563*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2200450 | encode(qd, 22, 12) | encode(qm, 5, 0) | encode(qn, 7, 16));
564*4bdc9457SAndroid Build Coastguard Worker }
565*4bdc9457SAndroid Build Coastguard Worker 
vrshl_s32(QRegister qd,QRegister qm,QRegister qn)566*4bdc9457SAndroid Build Coastguard Worker void Assembler::vrshl_s32(QRegister qd, QRegister qm, QRegister qn) {
567*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF2200540 | encode(qd, 22, 12) | encode(qm, 5, 0) | encode(qn, 7, 16));
568*4bdc9457SAndroid Build Coastguard Worker }
569*4bdc9457SAndroid Build Coastguard Worker 
vsdot_s8(QRegister qd,QRegister qn,DRegisterLane dm)570*4bdc9457SAndroid Build Coastguard Worker void Assembler::vsdot_s8(QRegister qd, QRegister qn, DRegisterLane dm) {
571*4bdc9457SAndroid Build Coastguard Worker   if (dm.lane > 1) {
572*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidLaneIndex;
573*4bdc9457SAndroid Build Coastguard Worker     return;
574*4bdc9457SAndroid Build Coastguard Worker   }
575*4bdc9457SAndroid Build Coastguard Worker   emit32(0xFE200D40 | encode(qd, 22, 12) | encode(qn, 7, 16) | dm.lane << 5 | dm.code);
576*4bdc9457SAndroid Build Coastguard Worker }
577*4bdc9457SAndroid Build Coastguard Worker 
vst1(DataSize size,DRegisterList regs,MemOperand op)578*4bdc9457SAndroid Build Coastguard Worker void Assembler::vst1(DataSize size, DRegisterList regs, MemOperand op) {
579*4bdc9457SAndroid Build Coastguard Worker   const uint8_t type = encode_regs_length_to_type(regs);
580*4bdc9457SAndroid Build Coastguard Worker   if (!type) {
581*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
582*4bdc9457SAndroid Build Coastguard Worker     return;
583*4bdc9457SAndroid Build Coastguard Worker   }
584*4bdc9457SAndroid Build Coastguard Worker 
585*4bdc9457SAndroid Build Coastguard Worker   const uint32_t rm = op.mode() == AddressingMode::kPostIndexed ? 0xD : 0xF;
586*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF4000000 | encode(regs.start, 22, 12) | op.base().code << 16 | type << 8 | size << 6 | rm);
587*4bdc9457SAndroid Build Coastguard Worker }
588*4bdc9457SAndroid Build Coastguard Worker 
vst1(DataSize size,DRegisterList regs,MemOperand op,CoreRegister rm)589*4bdc9457SAndroid Build Coastguard Worker void Assembler::vst1(DataSize size, DRegisterList regs, MemOperand op, CoreRegister rm) {
590*4bdc9457SAndroid Build Coastguard Worker   if (rm.code == 0b1101 || rm.code == 0b1111) {
591*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
592*4bdc9457SAndroid Build Coastguard Worker     return;
593*4bdc9457SAndroid Build Coastguard Worker   }
594*4bdc9457SAndroid Build Coastguard Worker 
595*4bdc9457SAndroid Build Coastguard Worker   const uint8_t type = encode_regs_length_to_type(regs);
596*4bdc9457SAndroid Build Coastguard Worker   if (!type) {
597*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
598*4bdc9457SAndroid Build Coastguard Worker     return;
599*4bdc9457SAndroid Build Coastguard Worker   }
600*4bdc9457SAndroid Build Coastguard Worker 
601*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF4000000 | encode(regs.start, 22, 12) | op.base().code << 16 | type << 8 | size << 6 | rm.code);
602*4bdc9457SAndroid Build Coastguard Worker }
603*4bdc9457SAndroid Build Coastguard Worker 
vst1(DataSize size,DRegisterLane dd,MemOperand op)604*4bdc9457SAndroid Build Coastguard Worker void Assembler::vst1(DataSize size, DRegisterLane dd, MemOperand op) {
605*4bdc9457SAndroid Build Coastguard Worker   if ((size == k8 && dd.lane > 7) || (size == k16 && dd.lane > 3) || (size == k32 && dd.lane > 1)) {
606*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidLaneIndex;
607*4bdc9457SAndroid Build Coastguard Worker     return;
608*4bdc9457SAndroid Build Coastguard Worker   }
609*4bdc9457SAndroid Build Coastguard Worker 
610*4bdc9457SAndroid Build Coastguard Worker   const uint8_t shift = size == k8 ? 5 : size == k16 ? 6 : 7;
611*4bdc9457SAndroid Build Coastguard Worker   const uint32_t rm = op.mode() == AddressingMode::kPostIndexed ? 0xD : 0xF;
612*4bdc9457SAndroid Build Coastguard Worker   emit32(0xF4800000 | encode(dd, 22, 12) | op.base().code << 16 | size << 10 | dd.lane << shift | rm);
613*4bdc9457SAndroid Build Coastguard Worker }
614*4bdc9457SAndroid Build Coastguard Worker 
vstm(MemOperand rn,DRegisterList regs)615*4bdc9457SAndroid Build Coastguard Worker void Assembler::vstm(MemOperand rn, DRegisterList regs) {
616*4bdc9457SAndroid Build Coastguard Worker   if (invalid_register_list(regs)) {
617*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidRegisterListLength;
618*4bdc9457SAndroid Build Coastguard Worker     return;
619*4bdc9457SAndroid Build Coastguard Worker   }
620*4bdc9457SAndroid Build Coastguard Worker   uint32_t w = (rn.mode() == AddressingMode::kOffset ? 0 : 1) << 21;
621*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0C800B00 | w | rn.base().code << 16 |  encode(regs.start, 22, 12) | regs.length << 1);
622*4bdc9457SAndroid Build Coastguard Worker }
623*4bdc9457SAndroid Build Coastguard Worker 
vstr(SRegister rn,MemOperand op)624*4bdc9457SAndroid Build Coastguard Worker void Assembler::vstr(SRegister rn, MemOperand op) {
625*4bdc9457SAndroid Build Coastguard Worker   const uint32_t offset = std::abs(op.offset());
626*4bdc9457SAndroid Build Coastguard Worker   if (op.mode() != AddressingMode::kOffset || offset > kUint10Max || offset % 4 != 0) {
627*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
628*4bdc9457SAndroid Build Coastguard Worker     return;
629*4bdc9457SAndroid Build Coastguard Worker   }
630*4bdc9457SAndroid Build Coastguard Worker   emit32(kAL | 0x0D000A00 | op.u() << 23 | op.base().code << 16 | encode(rn, 22, 12) | offset >> 2);
631*4bdc9457SAndroid Build Coastguard Worker }
632*4bdc9457SAndroid Build Coastguard Worker 
align(uint8_t n)633*4bdc9457SAndroid Build Coastguard Worker void Assembler::align(uint8_t n) {
634*4bdc9457SAndroid Build Coastguard Worker   if (!is_po2(n) || (n % kInstructionSizeInBytes != 0)) {
635*4bdc9457SAndroid Build Coastguard Worker     error_ = Error::kInvalidOperand;
636*4bdc9457SAndroid Build Coastguard Worker     return;
637*4bdc9457SAndroid Build Coastguard Worker   }
638*4bdc9457SAndroid Build Coastguard Worker 
639*4bdc9457SAndroid Build Coastguard Worker   uintptr_t cursor = reinterpret_cast<uintptr_t>(cursor_);
640*4bdc9457SAndroid Build Coastguard Worker   const uintptr_t target = round_up_po2(cursor, n);
641*4bdc9457SAndroid Build Coastguard Worker   while (cursor < target) {
642*4bdc9457SAndroid Build Coastguard Worker     nop();
643*4bdc9457SAndroid Build Coastguard Worker     cursor += kInstructionSizeInBytes;
644*4bdc9457SAndroid Build Coastguard Worker   }
645*4bdc9457SAndroid Build Coastguard Worker }
646*4bdc9457SAndroid Build Coastguard Worker 
647*4bdc9457SAndroid Build Coastguard Worker }  // namespace aarch32
648*4bdc9457SAndroid Build Coastguard Worker }  // namespace xnnpack
649