1*4bdc9457SAndroid Build Coastguard Worker // Copyright 2022 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/aarch64-assembler.h>
7*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/common.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
12*4bdc9457SAndroid Build Coastguard Worker namespace xnnpack {
13*4bdc9457SAndroid Build Coastguard Worker namespace aarch64 {
14*4bdc9457SAndroid Build Coastguard Worker // Min and max values for the imm7 for ldp, will be shifted right by 3 when encoding.
15*4bdc9457SAndroid Build Coastguard Worker constexpr int32_t kImm7Min = -512;
16*4bdc9457SAndroid Build Coastguard Worker constexpr int32_t kImm7Max = 504;
17*4bdc9457SAndroid Build Coastguard Worker constexpr uint32_t kImm7Mask = 0x7F;
18*4bdc9457SAndroid Build Coastguard Worker // Max value for imm12, will be shifted right by 3 when encoding.
19*4bdc9457SAndroid Build Coastguard Worker constexpr int32_t kImm12Max = 32760;
20*4bdc9457SAndroid Build Coastguard Worker constexpr uint32_t kUint12Max = 4095;
21*4bdc9457SAndroid Build Coastguard Worker
22*4bdc9457SAndroid Build Coastguard Worker constexpr int32_t kInt9Max = 255;
23*4bdc9457SAndroid Build Coastguard Worker constexpr int32_t kInt9Min = -256;
24*4bdc9457SAndroid Build Coastguard Worker constexpr uint32_t kImm9Mask = 0x1FF;
25*4bdc9457SAndroid Build Coastguard Worker
26*4bdc9457SAndroid Build Coastguard Worker // Constants used for checking branch offset bounds.
27*4bdc9457SAndroid Build Coastguard Worker // Conditional bounds are +/-1MB.
28*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kConditionalBranchImmMax = 1048572;
29*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kConditionalBranchImmMin = -1048576;
30*4bdc9457SAndroid Build Coastguard Worker // TBZ and TBNZ bounds are +/-32KB.
31*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kTbxzImmMax = 32764;
32*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kTbxzImmMin = -32768;
33*4bdc9457SAndroid Build Coastguard Worker // Unconditional bounds are +/-128MB.
34*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kUnconditionalBranchImmMax = 134217727;
35*4bdc9457SAndroid Build Coastguard Worker constexpr ptrdiff_t kUnconditionalBranchImmMin = -134217728;
36*4bdc9457SAndroid Build Coastguard Worker
37*4bdc9457SAndroid Build Coastguard Worker constexpr uint32_t kConditionalImmMask = 0x0007FFFF;
38*4bdc9457SAndroid Build Coastguard Worker constexpr uint32_t kTbxzImmMask = 0x3FFF;
39*4bdc9457SAndroid Build Coastguard Worker constexpr uint32_t kUnconditionalImmMask = 0x03FFFFFF;
40*4bdc9457SAndroid Build Coastguard Worker
rd(Reg rn)41*4bdc9457SAndroid Build Coastguard Worker template <typename Reg> inline uint32_t rd(Reg rn) { return rn.code; }
rt(Reg rn)42*4bdc9457SAndroid Build Coastguard Worker template <typename Reg> inline uint32_t rt(Reg rn) { return rn.code; }
rt2(Reg rn)43*4bdc9457SAndroid Build Coastguard Worker template <typename Reg> inline uint32_t rt2(Reg rn) { return rn.code << 10; }
rm(Reg rn)44*4bdc9457SAndroid Build Coastguard Worker template <typename Reg> inline uint32_t rm(Reg rn) { return rn.code << 16; }
rn(Reg rn)45*4bdc9457SAndroid Build Coastguard Worker template <typename Reg> inline uint32_t rn(Reg rn) { return rn.code << 5; }
q(VRegister vt)46*4bdc9457SAndroid Build Coastguard Worker inline uint32_t q(VRegister vt) { return vt.q << 30; }
size(VRegister vt)47*4bdc9457SAndroid Build Coastguard Worker inline uint32_t size(VRegister vt) { return vt.size << 10; }
fp_sz(VRegister vn)48*4bdc9457SAndroid Build Coastguard Worker inline uint32_t fp_sz(VRegister vn) { return vn.is_s() ? 0 : 1 << 22; }
postindex(MemOperand op)49*4bdc9457SAndroid Build Coastguard Worker inline uint32_t postindex(MemOperand op) { return (op.mode == AddressingMode::kPostIndex) ? 0 : 1 << 24; }
wb(MemOperand op)50*4bdc9457SAndroid Build Coastguard Worker inline uint32_t wb(MemOperand op) { return op.mode == AddressingMode::kOffset ? 0 : 1 << 23; }
51*4bdc9457SAndroid Build Coastguard Worker
imm9(int32_t imm)52*4bdc9457SAndroid Build Coastguard Worker inline uint32_t imm9(int32_t imm) {
53*4bdc9457SAndroid Build Coastguard Worker assert(!(imm < kInt9Min || imm > kInt9Max));
54*4bdc9457SAndroid Build Coastguard Worker return (imm & kImm9Mask) << 12;
55*4bdc9457SAndroid Build Coastguard Worker }
56*4bdc9457SAndroid Build Coastguard Worker
is_same_shape(VRegister vt1,VRegister vt2)57*4bdc9457SAndroid Build Coastguard Worker inline bool is_same_shape(VRegister vt1, VRegister vt2) {
58*4bdc9457SAndroid Build Coastguard Worker return vt1.size == vt2.size && vt1.q == vt2.q;
59*4bdc9457SAndroid Build Coastguard Worker }
60*4bdc9457SAndroid Build Coastguard Worker
61*4bdc9457SAndroid Build Coastguard Worker template <typename Reg, typename... Regs>
is_same_shape(Reg reg1,Reg reg2,Regs...regs)62*4bdc9457SAndroid Build Coastguard Worker inline bool is_same_shape(Reg reg1, Reg reg2, Regs... regs) {
63*4bdc9457SAndroid Build Coastguard Worker return is_same_shape(reg1, reg2) && is_same_shape(reg2, regs...);
64*4bdc9457SAndroid Build Coastguard Worker }
65*4bdc9457SAndroid Build Coastguard Worker
is_same_shape(VRegisterList vs)66*4bdc9457SAndroid Build Coastguard Worker inline bool is_same_shape(VRegisterList vs) {
67*4bdc9457SAndroid Build Coastguard Worker switch (vs.length) {
68*4bdc9457SAndroid Build Coastguard Worker case 1:
69*4bdc9457SAndroid Build Coastguard Worker return true;
70*4bdc9457SAndroid Build Coastguard Worker case 2:
71*4bdc9457SAndroid Build Coastguard Worker return is_same_shape(vs.vt1, vs.vt2);
72*4bdc9457SAndroid Build Coastguard Worker case 3:
73*4bdc9457SAndroid Build Coastguard Worker return is_same_shape(vs.vt1, vs.vt2, vs.vt3);
74*4bdc9457SAndroid Build Coastguard Worker case 4:
75*4bdc9457SAndroid Build Coastguard Worker return is_same_shape(vs.vt1, vs.vt2, vs.vt3, vs.vt4);
76*4bdc9457SAndroid Build Coastguard Worker default:
77*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
78*4bdc9457SAndroid Build Coastguard Worker }
79*4bdc9457SAndroid Build Coastguard Worker }
80*4bdc9457SAndroid Build Coastguard Worker
is_same_data_type(VRegister vt1,VRegisterLane vt2)81*4bdc9457SAndroid Build Coastguard Worker inline bool is_same_data_type(VRegister vt1, VRegisterLane vt2) {
82*4bdc9457SAndroid Build Coastguard Worker return vt1.size == vt2.size;
83*4bdc9457SAndroid Build Coastguard Worker }
84*4bdc9457SAndroid Build Coastguard Worker
is_consecutive(VRegister vt1,VRegister vt2)85*4bdc9457SAndroid Build Coastguard Worker inline bool is_consecutive(VRegister vt1, VRegister vt2) {
86*4bdc9457SAndroid Build Coastguard Worker return (vt1.code + 1) % 32 == vt2.code;
87*4bdc9457SAndroid Build Coastguard Worker }
88*4bdc9457SAndroid Build Coastguard Worker
89*4bdc9457SAndroid Build Coastguard Worker template <typename Reg, typename... Regs>
is_consecutive(Reg reg1,Reg reg2,Regs...regs)90*4bdc9457SAndroid Build Coastguard Worker inline bool is_consecutive(Reg reg1, Reg reg2, Regs... regs) {
91*4bdc9457SAndroid Build Coastguard Worker return is_consecutive(reg1, reg2) && is_consecutive(reg2, regs...);
92*4bdc9457SAndroid Build Coastguard Worker }
93*4bdc9457SAndroid Build Coastguard Worker
is_consecutive(VRegisterList vs)94*4bdc9457SAndroid Build Coastguard Worker inline bool is_consecutive(VRegisterList vs) {
95*4bdc9457SAndroid Build Coastguard Worker switch (vs.length) {
96*4bdc9457SAndroid Build Coastguard Worker case 1:
97*4bdc9457SAndroid Build Coastguard Worker return true;
98*4bdc9457SAndroid Build Coastguard Worker case 2:
99*4bdc9457SAndroid Build Coastguard Worker return is_consecutive(vs.vt1, vs.vt2);
100*4bdc9457SAndroid Build Coastguard Worker case 3:
101*4bdc9457SAndroid Build Coastguard Worker return is_consecutive(vs.vt1, vs.vt2, vs.vt3);
102*4bdc9457SAndroid Build Coastguard Worker case 4:
103*4bdc9457SAndroid Build Coastguard Worker return is_consecutive(vs.vt1, vs.vt2, vs.vt3, vs.vt4);
104*4bdc9457SAndroid Build Coastguard Worker default:
105*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
106*4bdc9457SAndroid Build Coastguard Worker }
107*4bdc9457SAndroid Build Coastguard Worker }
108*4bdc9457SAndroid Build Coastguard Worker
109*4bdc9457SAndroid Build Coastguard Worker // Check if a branch offset is valid, it must fit in 19 bits.
branch_offset_valid(ptrdiff_t offset,BranchType branch_type)110*4bdc9457SAndroid Build Coastguard Worker inline bool branch_offset_valid(ptrdiff_t offset, BranchType branch_type) {
111*4bdc9457SAndroid Build Coastguard Worker switch (branch_type) {
112*4bdc9457SAndroid Build Coastguard Worker case BranchType::kConditional:
113*4bdc9457SAndroid Build Coastguard Worker return offset < kConditionalBranchImmMax && offset > kConditionalBranchImmMin;
114*4bdc9457SAndroid Build Coastguard Worker case BranchType::kTbxz:
115*4bdc9457SAndroid Build Coastguard Worker return offset < kTbxzImmMax && offset > kTbxzImmMin;
116*4bdc9457SAndroid Build Coastguard Worker case BranchType::kUnconditional:
117*4bdc9457SAndroid Build Coastguard Worker return offset < kUnconditionalBranchImmMax && offset > kUnconditionalBranchImmMin;
118*4bdc9457SAndroid Build Coastguard Worker default:
119*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
120*4bdc9457SAndroid Build Coastguard Worker }
121*4bdc9457SAndroid Build Coastguard Worker return false;
122*4bdc9457SAndroid Build Coastguard Worker }
123*4bdc9457SAndroid Build Coastguard Worker
instruction_branch_type(uint32_t instr)124*4bdc9457SAndroid Build Coastguard Worker inline BranchType instruction_branch_type(uint32_t instr) {
125*4bdc9457SAndroid Build Coastguard Worker const uint32_t masked = instr & 0xFE000000;
126*4bdc9457SAndroid Build Coastguard Worker switch (masked) {
127*4bdc9457SAndroid Build Coastguard Worker case 0xB6000000:
128*4bdc9457SAndroid Build Coastguard Worker case 0x36000000:
129*4bdc9457SAndroid Build Coastguard Worker return BranchType::kTbxz;
130*4bdc9457SAndroid Build Coastguard Worker case 0x54000000:
131*4bdc9457SAndroid Build Coastguard Worker return BranchType::kConditional;
132*4bdc9457SAndroid Build Coastguard Worker case 0x14000000:
133*4bdc9457SAndroid Build Coastguard Worker case 0x16000000:
134*4bdc9457SAndroid Build Coastguard Worker return BranchType::kUnconditional;
135*4bdc9457SAndroid Build Coastguard Worker default:
136*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
137*4bdc9457SAndroid Build Coastguard Worker }
138*4bdc9457SAndroid Build Coastguard Worker }
139*4bdc9457SAndroid Build Coastguard Worker
mask(BranchType branch_type)140*4bdc9457SAndroid Build Coastguard Worker inline uint32_t mask(BranchType branch_type) {
141*4bdc9457SAndroid Build Coastguard Worker switch (branch_type) {
142*4bdc9457SAndroid Build Coastguard Worker case BranchType::kConditional:
143*4bdc9457SAndroid Build Coastguard Worker return kConditionalImmMask;
144*4bdc9457SAndroid Build Coastguard Worker case BranchType::kTbxz:
145*4bdc9457SAndroid Build Coastguard Worker return kTbxzImmMask;
146*4bdc9457SAndroid Build Coastguard Worker case BranchType::kUnconditional:
147*4bdc9457SAndroid Build Coastguard Worker return kUnconditionalImmMask;
148*4bdc9457SAndroid Build Coastguard Worker default:
149*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
150*4bdc9457SAndroid Build Coastguard Worker }
151*4bdc9457SAndroid Build Coastguard Worker }
152*4bdc9457SAndroid Build Coastguard Worker
shift(BranchType branch_type)153*4bdc9457SAndroid Build Coastguard Worker inline uint8_t shift(BranchType branch_type) {
154*4bdc9457SAndroid Build Coastguard Worker switch (branch_type) {
155*4bdc9457SAndroid Build Coastguard Worker case BranchType::kConditional:
156*4bdc9457SAndroid Build Coastguard Worker return 5;
157*4bdc9457SAndroid Build Coastguard Worker case BranchType::kTbxz:
158*4bdc9457SAndroid Build Coastguard Worker return 5;
159*4bdc9457SAndroid Build Coastguard Worker case BranchType::kUnconditional:
160*4bdc9457SAndroid Build Coastguard Worker return 0;
161*4bdc9457SAndroid Build Coastguard Worker default:
162*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
163*4bdc9457SAndroid Build Coastguard Worker }
164*4bdc9457SAndroid Build Coastguard Worker }
165*4bdc9457SAndroid Build Coastguard Worker
branch_imm(ptrdiff_t offset,BranchType bt)166*4bdc9457SAndroid Build Coastguard Worker inline uint32_t branch_imm(ptrdiff_t offset, BranchType bt) {
167*4bdc9457SAndroid Build Coastguard Worker return ((offset >> kInstructionSizeInBytesLog2) & mask(bt)) << shift(bt);
168*4bdc9457SAndroid Build Coastguard Worker }
169*4bdc9457SAndroid Build Coastguard Worker
hl(VRegisterLane vl)170*4bdc9457SAndroid Build Coastguard Worker inline uint32_t hl(VRegisterLane vl) {
171*4bdc9457SAndroid Build Coastguard Worker if (vl.is_s()) {
172*4bdc9457SAndroid Build Coastguard Worker return (vl.lane & 1) << 21 | ((vl.lane & 2) << 10);
173*4bdc9457SAndroid Build Coastguard Worker } else {
174*4bdc9457SAndroid Build Coastguard Worker return (vl.lane & 1) << 11;
175*4bdc9457SAndroid Build Coastguard Worker }
176*4bdc9457SAndroid Build Coastguard Worker }
177*4bdc9457SAndroid Build Coastguard Worker
lane_index_valid(uint8_t q,uint8_t size,uint8_t lane)178*4bdc9457SAndroid Build Coastguard Worker inline bool lane_index_valid(uint8_t q, uint8_t size, uint8_t lane) {
179*4bdc9457SAndroid Build Coastguard Worker // The logic here is something like:
180*4bdc9457SAndroid Build Coastguard Worker // if (q && size == 0) {
181*4bdc9457SAndroid Build Coastguard Worker // return lane < 16;
182*4bdc9457SAndroid Build Coastguard Worker // } else if (q && size == 1) {
183*4bdc9457SAndroid Build Coastguard Worker // return lane < 8;
184*4bdc9457SAndroid Build Coastguard Worker // } else if (q && size == 2) {
185*4bdc9457SAndroid Build Coastguard Worker // return lane < 4;
186*4bdc9457SAndroid Build Coastguard Worker // } else if (q && size == 3) {
187*4bdc9457SAndroid Build Coastguard Worker // return lane < 2;
188*4bdc9457SAndroid Build Coastguard Worker // }
189*4bdc9457SAndroid Build Coastguard Worker // then repeat for !q with maximum lane size halved.
190*4bdc9457SAndroid Build Coastguard Worker // translated into this formula.
191*4bdc9457SAndroid Build Coastguard Worker return lane < ((q + 1) << (3 - size));
192*4bdc9457SAndroid Build Coastguard Worker }
193*4bdc9457SAndroid Build Coastguard Worker
load_store_opcode(uint8_t register_length)194*4bdc9457SAndroid Build Coastguard Worker inline uint8_t load_store_opcode(uint8_t register_length) {
195*4bdc9457SAndroid Build Coastguard Worker switch (register_length) {
196*4bdc9457SAndroid Build Coastguard Worker case 1:
197*4bdc9457SAndroid Build Coastguard Worker return 0x7;
198*4bdc9457SAndroid Build Coastguard Worker case 2:
199*4bdc9457SAndroid Build Coastguard Worker return 0xA;
200*4bdc9457SAndroid Build Coastguard Worker case 3:
201*4bdc9457SAndroid Build Coastguard Worker return 0x6;
202*4bdc9457SAndroid Build Coastguard Worker case 4:
203*4bdc9457SAndroid Build Coastguard Worker return 0x2;
204*4bdc9457SAndroid Build Coastguard Worker default:
205*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
206*4bdc9457SAndroid Build Coastguard Worker }
207*4bdc9457SAndroid Build Coastguard Worker }
208*4bdc9457SAndroid Build Coastguard Worker
imm7_offset_valid(int32_t imm,XRegister)209*4bdc9457SAndroid Build Coastguard Worker inline bool imm7_offset_valid(int32_t imm, XRegister) {
210*4bdc9457SAndroid Build Coastguard Worker return imm >= kImm7Min && imm <= kImm7Max && (imm & 0x7) == 0;
211*4bdc9457SAndroid Build Coastguard Worker }
212*4bdc9457SAndroid Build Coastguard Worker
imm7_offset_valid(int32_t imm,DRegister)213*4bdc9457SAndroid Build Coastguard Worker inline bool imm7_offset_valid(int32_t imm, DRegister) {
214*4bdc9457SAndroid Build Coastguard Worker return imm >= kImm7Min && imm <= kImm7Max && (imm & 0x7) == 0;
215*4bdc9457SAndroid Build Coastguard Worker }
216*4bdc9457SAndroid Build Coastguard Worker
imm7_offset_valid(int32_t imm,QRegister)217*4bdc9457SAndroid Build Coastguard Worker inline bool imm7_offset_valid(int32_t imm, QRegister) {
218*4bdc9457SAndroid Build Coastguard Worker return imm >= (kImm7Min * 2) && imm <= (kImm7Max * 2) && (imm & 0xF) == 0;
219*4bdc9457SAndroid Build Coastguard Worker }
220*4bdc9457SAndroid Build Coastguard Worker
221*4bdc9457SAndroid Build Coastguard Worker // Base instructions.
222*4bdc9457SAndroid Build Coastguard Worker
add(XRegister xd,XRegister xn,uint16_t imm12)223*4bdc9457SAndroid Build Coastguard Worker void Assembler::add(XRegister xd, XRegister xn, uint16_t imm12) {
224*4bdc9457SAndroid Build Coastguard Worker // The instruction supports larger numbers using the shift by (left shift by 12), but that's unused in kernels.
225*4bdc9457SAndroid Build Coastguard Worker if (imm12 > kUint12Max) {
226*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
227*4bdc9457SAndroid Build Coastguard Worker return;
228*4bdc9457SAndroid Build Coastguard Worker }
229*4bdc9457SAndroid Build Coastguard Worker
230*4bdc9457SAndroid Build Coastguard Worker emit32(0x91000000 | imm12 << 10 | rn(xn) | rd(xd));
231*4bdc9457SAndroid Build Coastguard Worker }
232*4bdc9457SAndroid Build Coastguard Worker
add(XRegister xd,XRegister xn,XRegister xm)233*4bdc9457SAndroid Build Coastguard Worker void Assembler::add(XRegister xd, XRegister xn, XRegister xm) {
234*4bdc9457SAndroid Build Coastguard Worker emit32(0x8B000000 | rd(xd) | rn(xn) | rm(xm));
235*4bdc9457SAndroid Build Coastguard Worker }
236*4bdc9457SAndroid Build Coastguard Worker
b(Label & l)237*4bdc9457SAndroid Build Coastguard Worker void Assembler::b(Label& l) {
238*4bdc9457SAndroid Build Coastguard Worker return branch_to_label(0x14000000, BranchType::kUnconditional, l);
239*4bdc9457SAndroid Build Coastguard Worker }
240*4bdc9457SAndroid Build Coastguard Worker
cmp(XRegister xn,uint16_t imm12)241*4bdc9457SAndroid Build Coastguard Worker void Assembler::cmp(XRegister xn, uint16_t imm12) {
242*4bdc9457SAndroid Build Coastguard Worker if (imm12 > kUint12Max) {
243*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
244*4bdc9457SAndroid Build Coastguard Worker return;
245*4bdc9457SAndroid Build Coastguard Worker }
246*4bdc9457SAndroid Build Coastguard Worker emit32(0xF100001F | imm12 << 10 | rn(xn));
247*4bdc9457SAndroid Build Coastguard Worker }
248*4bdc9457SAndroid Build Coastguard Worker
cmp(XRegister xn,XRegister xm)249*4bdc9457SAndroid Build Coastguard Worker void Assembler::cmp(XRegister xn, XRegister xm) {
250*4bdc9457SAndroid Build Coastguard Worker emit32(0xEB00001F | rm(xm) | rn(xn));
251*4bdc9457SAndroid Build Coastguard Worker }
252*4bdc9457SAndroid Build Coastguard Worker
csel(XRegister xd,XRegister xn,XRegister xm,Condition c)253*4bdc9457SAndroid Build Coastguard Worker void Assembler::csel(XRegister xd, XRegister xn, XRegister xm, Condition c) {
254*4bdc9457SAndroid Build Coastguard Worker emit32(0x9A800000 | rm(xm) | c << 12 | rn(xn) | rd(xd));
255*4bdc9457SAndroid Build Coastguard Worker }
256*4bdc9457SAndroid Build Coastguard Worker
hlt()257*4bdc9457SAndroid Build Coastguard Worker void Assembler::hlt() {
258*4bdc9457SAndroid Build Coastguard Worker emit32(0xD4400000);
259*4bdc9457SAndroid Build Coastguard Worker }
260*4bdc9457SAndroid Build Coastguard Worker
ldp(XRegister xt1,XRegister xt2,MemOperand xn)261*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldp(XRegister xt1, XRegister xt2, MemOperand xn) {
262*4bdc9457SAndroid Build Coastguard Worker if (!imm7_offset_valid(xn.offset, xt1)) {
263*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
264*4bdc9457SAndroid Build Coastguard Worker return;
265*4bdc9457SAndroid Build Coastguard Worker }
266*4bdc9457SAndroid Build Coastguard Worker
267*4bdc9457SAndroid Build Coastguard Worker const uint32_t offset = (xn.offset >> 3) & kImm7Mask;
268*4bdc9457SAndroid Build Coastguard Worker
269*4bdc9457SAndroid Build Coastguard Worker emit32(0xA8400000 | postindex(xn) | wb(xn) | offset << 15 | rt2(xt2) | rn(xn.base) | xt1.code);
270*4bdc9457SAndroid Build Coastguard Worker }
271*4bdc9457SAndroid Build Coastguard Worker
ldp(XRegister xt1,XRegister xt2,MemOperand xn,int32_t imm)272*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldp(XRegister xt1, XRegister xt2, MemOperand xn, int32_t imm) {
273*4bdc9457SAndroid Build Coastguard Worker if (xn.offset != 0) {
274*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
275*4bdc9457SAndroid Build Coastguard Worker return;
276*4bdc9457SAndroid Build Coastguard Worker }
277*4bdc9457SAndroid Build Coastguard Worker return ldp(xt1, xt2, {xn.base, imm, AddressingMode::kPostIndex});
278*4bdc9457SAndroid Build Coastguard Worker }
279*4bdc9457SAndroid Build Coastguard Worker
ldr(XRegister xt,MemOperand xn)280*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(XRegister xt, MemOperand xn) {
281*4bdc9457SAndroid Build Coastguard Worker const int32_t imm = xn.offset;
282*4bdc9457SAndroid Build Coastguard Worker if (xn.mode != AddressingMode::kOffset || imm < 0 || imm > (kUint12Max << 3) || (imm & 7) != 0) {
283*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
284*4bdc9457SAndroid Build Coastguard Worker return;
285*4bdc9457SAndroid Build Coastguard Worker }
286*4bdc9457SAndroid Build Coastguard Worker
287*4bdc9457SAndroid Build Coastguard Worker emit32(0xF9400000 | imm >> 3 << 10 | rn(xn.base) | xt.code);
288*4bdc9457SAndroid Build Coastguard Worker }
289*4bdc9457SAndroid Build Coastguard Worker
ldr(XRegister xt,MemOperand xn,int32_t imm)290*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(XRegister xt, MemOperand xn, int32_t imm) {
291*4bdc9457SAndroid Build Coastguard Worker if (imm < kInt9Min || imm > kInt9Max) {
292*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
293*4bdc9457SAndroid Build Coastguard Worker return;
294*4bdc9457SAndroid Build Coastguard Worker }
295*4bdc9457SAndroid Build Coastguard Worker
296*4bdc9457SAndroid Build Coastguard Worker emit32(0xF8400400 | imm9(imm) | rn(xn.base) | rt(xt));
297*4bdc9457SAndroid Build Coastguard Worker }
298*4bdc9457SAndroid Build Coastguard Worker
mov(XRegister xd,XRegister xn)299*4bdc9457SAndroid Build Coastguard Worker void Assembler::mov(XRegister xd, XRegister xn) {
300*4bdc9457SAndroid Build Coastguard Worker emit32(0xAA0003E0 | rm(xn) | rd(xd));
301*4bdc9457SAndroid Build Coastguard Worker }
302*4bdc9457SAndroid Build Coastguard Worker
nop()303*4bdc9457SAndroid Build Coastguard Worker void Assembler::nop() {
304*4bdc9457SAndroid Build Coastguard Worker emit32(0xD503201F);
305*4bdc9457SAndroid Build Coastguard Worker }
306*4bdc9457SAndroid Build Coastguard Worker
prfm(PrefetchOp prfop,MemOperand xn)307*4bdc9457SAndroid Build Coastguard Worker void Assembler::prfm(PrefetchOp prfop, MemOperand xn) {
308*4bdc9457SAndroid Build Coastguard Worker if (xn.offset < 0 || xn.offset > kImm12Max) {
309*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
310*4bdc9457SAndroid Build Coastguard Worker return;
311*4bdc9457SAndroid Build Coastguard Worker }
312*4bdc9457SAndroid Build Coastguard Worker
313*4bdc9457SAndroid Build Coastguard Worker emit32(0xF9800000 | xn.offset >> 3 << 10 | rn(xn.base) | prfop);
314*4bdc9457SAndroid Build Coastguard Worker }
315*4bdc9457SAndroid Build Coastguard Worker
ret()316*4bdc9457SAndroid Build Coastguard Worker void Assembler::ret() {
317*4bdc9457SAndroid Build Coastguard Worker emit32(0xD65F0000 | rn(x30));
318*4bdc9457SAndroid Build Coastguard Worker }
319*4bdc9457SAndroid Build Coastguard Worker
stp(XRegister xt1,XRegister xt2,MemOperand xn)320*4bdc9457SAndroid Build Coastguard Worker void Assembler::stp(XRegister xt1, XRegister xt2, MemOperand xn) {
321*4bdc9457SAndroid Build Coastguard Worker if (!imm7_offset_valid(xn.offset, xt1)) {
322*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
323*4bdc9457SAndroid Build Coastguard Worker return;
324*4bdc9457SAndroid Build Coastguard Worker }
325*4bdc9457SAndroid Build Coastguard Worker
326*4bdc9457SAndroid Build Coastguard Worker const uint32_t offset = (xn.offset >> 3) & kImm7Mask;
327*4bdc9457SAndroid Build Coastguard Worker emit32(0xA9000000 | wb(xn) | offset << 15 | rt2(xt2) | rn(xn.base) | rt(xt1));
328*4bdc9457SAndroid Build Coastguard Worker }
329*4bdc9457SAndroid Build Coastguard Worker
str(XRegister xt1,MemOperand xn)330*4bdc9457SAndroid Build Coastguard Worker void Assembler::str(XRegister xt1, MemOperand xn) {
331*4bdc9457SAndroid Build Coastguard Worker const int32_t offset = xn.offset;
332*4bdc9457SAndroid Build Coastguard Worker if (xn.mode == AddressingMode::kPreIndex) {
333*4bdc9457SAndroid Build Coastguard Worker if (offset < kInt9Min || offset > kInt9Max) {
334*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
335*4bdc9457SAndroid Build Coastguard Worker return;
336*4bdc9457SAndroid Build Coastguard Worker }
337*4bdc9457SAndroid Build Coastguard Worker emit32(0xF8000C00 | imm9(offset) | rn(xn.base) | rt(xt1));
338*4bdc9457SAndroid Build Coastguard Worker } else if (xn.mode == AddressingMode::kOffset) {
339*4bdc9457SAndroid Build Coastguard Worker if (offset < 0 || offset > kImm12Max || offset % 8 != 0) {
340*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
341*4bdc9457SAndroid Build Coastguard Worker return;
342*4bdc9457SAndroid Build Coastguard Worker }
343*4bdc9457SAndroid Build Coastguard Worker emit32(0xF9000000 | offset >> 3 << 10 | rn(xn.base) | rt(xt1));
344*4bdc9457SAndroid Build Coastguard Worker } else {
345*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
346*4bdc9457SAndroid Build Coastguard Worker }
347*4bdc9457SAndroid Build Coastguard Worker }
348*4bdc9457SAndroid Build Coastguard Worker
sub(XRegister xd,XRegister xn,XRegister xm)349*4bdc9457SAndroid Build Coastguard Worker void Assembler::sub(XRegister xd, XRegister xn, XRegister xm) {
350*4bdc9457SAndroid Build Coastguard Worker emit32(0xCB000000 | rm(xm) | rn(xn) | rd(xd));
351*4bdc9457SAndroid Build Coastguard Worker }
352*4bdc9457SAndroid Build Coastguard Worker
subs(XRegister xd,XRegister xn,uint16_t imm12)353*4bdc9457SAndroid Build Coastguard Worker void Assembler::subs(XRegister xd, XRegister xn, uint16_t imm12) {
354*4bdc9457SAndroid Build Coastguard Worker if (imm12 > kUint12Max) {
355*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
356*4bdc9457SAndroid Build Coastguard Worker return;
357*4bdc9457SAndroid Build Coastguard Worker }
358*4bdc9457SAndroid Build Coastguard Worker
359*4bdc9457SAndroid Build Coastguard Worker emit32(0xF1000000 | imm12 << 10 | rn(xn) | rd(xd));
360*4bdc9457SAndroid Build Coastguard Worker }
361*4bdc9457SAndroid Build Coastguard Worker
tbnz(XRegister xd,uint8_t bit,Label & l)362*4bdc9457SAndroid Build Coastguard Worker void Assembler::tbnz(XRegister xd, uint8_t bit, Label& l) {
363*4bdc9457SAndroid Build Coastguard Worker return tb_helper(0x37000000, xd, bit, l);
364*4bdc9457SAndroid Build Coastguard Worker }
365*4bdc9457SAndroid Build Coastguard Worker
tbz(XRegister xd,uint8_t bit,Label & l)366*4bdc9457SAndroid Build Coastguard Worker void Assembler::tbz(XRegister xd, uint8_t bit, Label& l) {
367*4bdc9457SAndroid Build Coastguard Worker return tb_helper(0x36000000, xd, bit, l);
368*4bdc9457SAndroid Build Coastguard Worker }
369*4bdc9457SAndroid Build Coastguard Worker
tst(XRegister xn,uint8_t imm)370*4bdc9457SAndroid Build Coastguard Worker void Assembler::tst(XRegister xn, uint8_t imm) {
371*4bdc9457SAndroid Build Coastguard Worker // Encoding of immediate is quite complicated, we only support po2-1, which is what assembly microkernel uses.
372*4bdc9457SAndroid Build Coastguard Worker uint32_t imm_po2 = imm + 1;
373*4bdc9457SAndroid Build Coastguard Worker if (!is_po2(imm_po2)) {
374*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kUnimplemented;
375*4bdc9457SAndroid Build Coastguard Worker return;
376*4bdc9457SAndroid Build Coastguard Worker }
377*4bdc9457SAndroid Build Coastguard Worker
378*4bdc9457SAndroid Build Coastguard Worker const uint32_t imm_s = (math_ctz_u32(imm_po2) - 1) << 10;
379*4bdc9457SAndroid Build Coastguard Worker emit32(0xF240001F | imm_s | rn(xn));
380*4bdc9457SAndroid Build Coastguard Worker }
381*4bdc9457SAndroid Build Coastguard Worker
382*4bdc9457SAndroid Build Coastguard Worker // SIMD instructions.
383*4bdc9457SAndroid Build Coastguard Worker
dup(DRegister dd,VRegisterLane vn)384*4bdc9457SAndroid Build Coastguard Worker void Assembler::dup(DRegister dd, VRegisterLane vn) {
385*4bdc9457SAndroid Build Coastguard Worker if (vn.size != 3 || vn.lane > 1) {
386*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
387*4bdc9457SAndroid Build Coastguard Worker return;
388*4bdc9457SAndroid Build Coastguard Worker }
389*4bdc9457SAndroid Build Coastguard Worker const uint8_t imm5 = 0b1000 | (vn.lane & 1) << 4;
390*4bdc9457SAndroid Build Coastguard Worker emit32(0x5E000400 | imm5 << 16 | rn(vn) | rd(dd));
391*4bdc9457SAndroid Build Coastguard Worker }
392*4bdc9457SAndroid Build Coastguard Worker
fabs(VRegister vd,VRegister vn)393*4bdc9457SAndroid Build Coastguard Worker void Assembler::fabs(VRegister vd, VRegister vn) {
394*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn)) {
395*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
396*4bdc9457SAndroid Build Coastguard Worker return;
397*4bdc9457SAndroid Build Coastguard Worker }
398*4bdc9457SAndroid Build Coastguard Worker
399*4bdc9457SAndroid Build Coastguard Worker emit32(0x0EA0F800 | q(vd) | fp_sz(vn) | rn(vn) | rd(vd));
400*4bdc9457SAndroid Build Coastguard Worker }
401*4bdc9457SAndroid Build Coastguard Worker
fadd(VRegister vd,VRegister vn,VRegister vm)402*4bdc9457SAndroid Build Coastguard Worker void Assembler::fadd(VRegister vd, VRegister vn, VRegister vm) {
403*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn, vm)) {
404*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
405*4bdc9457SAndroid Build Coastguard Worker return;
406*4bdc9457SAndroid Build Coastguard Worker }
407*4bdc9457SAndroid Build Coastguard Worker
408*4bdc9457SAndroid Build Coastguard Worker emit32(0x0E20D400 | q(vd) | fp_sz(vn) | rm(vm) | rn(vn) | rd(vd));
409*4bdc9457SAndroid Build Coastguard Worker }
410*4bdc9457SAndroid Build Coastguard Worker
fmax(VRegister vd,VRegister vn,VRegister vm)411*4bdc9457SAndroid Build Coastguard Worker void Assembler::fmax(VRegister vd, VRegister vn, VRegister vm) {
412*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn, vm)) {
413*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
414*4bdc9457SAndroid Build Coastguard Worker return;
415*4bdc9457SAndroid Build Coastguard Worker }
416*4bdc9457SAndroid Build Coastguard Worker
417*4bdc9457SAndroid Build Coastguard Worker emit32(0x0E20F400 | q(vd) | fp_sz(vn) | rm(vm) | rn(vn) | rd(vd));
418*4bdc9457SAndroid Build Coastguard Worker }
419*4bdc9457SAndroid Build Coastguard Worker
fmin(VRegister vd,VRegister vn,VRegister vm)420*4bdc9457SAndroid Build Coastguard Worker void Assembler::fmin(VRegister vd, VRegister vn, VRegister vm) {
421*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn, vm)) {
422*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
423*4bdc9457SAndroid Build Coastguard Worker return;
424*4bdc9457SAndroid Build Coastguard Worker }
425*4bdc9457SAndroid Build Coastguard Worker
426*4bdc9457SAndroid Build Coastguard Worker emit32(0x0EA0F400 | q(vd) | fp_sz(vn) | rm(vm) | rn(vn) | rd(vd));
427*4bdc9457SAndroid Build Coastguard Worker }
428*4bdc9457SAndroid Build Coastguard Worker
fmla(VRegister vd,VRegister vn,VRegisterLane vm)429*4bdc9457SAndroid Build Coastguard Worker void Assembler::fmla(VRegister vd, VRegister vn, VRegisterLane vm) {
430*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn) || !is_same_data_type(vd, vm)) {
431*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
432*4bdc9457SAndroid Build Coastguard Worker return;
433*4bdc9457SAndroid Build Coastguard Worker }
434*4bdc9457SAndroid Build Coastguard Worker if (!lane_index_valid(vd.q, vm.size, vm.lane)) {
435*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidLaneIndex;
436*4bdc9457SAndroid Build Coastguard Worker return;
437*4bdc9457SAndroid Build Coastguard Worker }
438*4bdc9457SAndroid Build Coastguard Worker
439*4bdc9457SAndroid Build Coastguard Worker emit32(0x0F801000 | q(vd) | fp_sz(vd) | hl(vm) | rm(vm) | rn(vn) | rd(vd));
440*4bdc9457SAndroid Build Coastguard Worker }
441*4bdc9457SAndroid Build Coastguard Worker
fmul(VRegister vd,VRegister vn,VRegister vm)442*4bdc9457SAndroid Build Coastguard Worker void Assembler::fmul(VRegister vd, VRegister vn, VRegister vm) {
443*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn, vm)) {
444*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
445*4bdc9457SAndroid Build Coastguard Worker return;
446*4bdc9457SAndroid Build Coastguard Worker }
447*4bdc9457SAndroid Build Coastguard Worker
448*4bdc9457SAndroid Build Coastguard Worker emit32(0x2E20DC00 | q(vd) | fp_sz(vn) | rm(vm) | rn(vn) | rd(vd));
449*4bdc9457SAndroid Build Coastguard Worker }
450*4bdc9457SAndroid Build Coastguard Worker
fneg(VRegister vd,VRegister vn)451*4bdc9457SAndroid Build Coastguard Worker void Assembler::fneg(VRegister vd, VRegister vn) {
452*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn)) {
453*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
454*4bdc9457SAndroid Build Coastguard Worker return;
455*4bdc9457SAndroid Build Coastguard Worker }
456*4bdc9457SAndroid Build Coastguard Worker
457*4bdc9457SAndroid Build Coastguard Worker emit32(0x2EA0F800 | q(vd) | fp_sz(vn) | rn(vn) | rd(vd));
458*4bdc9457SAndroid Build Coastguard Worker }
459*4bdc9457SAndroid Build Coastguard Worker
ld1(VRegisterList vs,MemOperand xn,int32_t imm)460*4bdc9457SAndroid Build Coastguard Worker void Assembler::ld1(VRegisterList vs, MemOperand xn, int32_t imm) {
461*4bdc9457SAndroid Build Coastguard Worker VRegister vt = vs.vt1;
462*4bdc9457SAndroid Build Coastguard Worker
463*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vs) || !is_consecutive(vs)) {
464*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
465*4bdc9457SAndroid Build Coastguard Worker return;
466*4bdc9457SAndroid Build Coastguard Worker }
467*4bdc9457SAndroid Build Coastguard Worker
468*4bdc9457SAndroid Build Coastguard Worker // imm must match number of bytes loaded.
469*4bdc9457SAndroid Build Coastguard Worker if ((vt.q + 1) * 8 * vs.length != imm) {
470*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
471*4bdc9457SAndroid Build Coastguard Worker return;
472*4bdc9457SAndroid Build Coastguard Worker }
473*4bdc9457SAndroid Build Coastguard Worker
474*4bdc9457SAndroid Build Coastguard Worker const uint8_t opcode = load_store_opcode(vs.length);
475*4bdc9457SAndroid Build Coastguard Worker
476*4bdc9457SAndroid Build Coastguard Worker emit32(0x0CDF0000 | q(vt) | opcode << 12 | size(vt) | rn(xn.base) | rt(vt));
477*4bdc9457SAndroid Build Coastguard Worker }
478*4bdc9457SAndroid Build Coastguard Worker
ld1r(VRegisterList xs,MemOperand xn)479*4bdc9457SAndroid Build Coastguard Worker void Assembler::ld1r(VRegisterList xs, MemOperand xn) {
480*4bdc9457SAndroid Build Coastguard Worker if (xs.length != 1 || xn.offset != 0) {
481*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
482*4bdc9457SAndroid Build Coastguard Worker return;
483*4bdc9457SAndroid Build Coastguard Worker }
484*4bdc9457SAndroid Build Coastguard Worker
485*4bdc9457SAndroid Build Coastguard Worker emit32(0x0D40C000 | q(xs.vt1) | size(xs.vt1) | rn(xn.base) | xs.vt1.code);
486*4bdc9457SAndroid Build Coastguard Worker }
487*4bdc9457SAndroid Build Coastguard Worker
ld2r(VRegisterList xs,MemOperand xn)488*4bdc9457SAndroid Build Coastguard Worker void Assembler::ld2r(VRegisterList xs, MemOperand xn) {
489*4bdc9457SAndroid Build Coastguard Worker if (xs.length != 2 || !is_same_shape(xs.vt1, xs.vt2) || xn.offset != 0 || !is_consecutive(xs)) {
490*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
491*4bdc9457SAndroid Build Coastguard Worker return;
492*4bdc9457SAndroid Build Coastguard Worker }
493*4bdc9457SAndroid Build Coastguard Worker
494*4bdc9457SAndroid Build Coastguard Worker emit32(0x0D60C000 | q(xs.vt1) | size(xs.vt1) | rn(xn.base) | xs.vt1.code);
495*4bdc9457SAndroid Build Coastguard Worker }
496*4bdc9457SAndroid Build Coastguard Worker
ld3r(VRegisterList xs,MemOperand xn)497*4bdc9457SAndroid Build Coastguard Worker void Assembler::ld3r(VRegisterList xs, MemOperand xn) {
498*4bdc9457SAndroid Build Coastguard Worker if (xs.length != 3 || !is_same_shape(xs.vt1, xs.vt2, xs.vt3) || xn.offset != 0 || !is_consecutive(xs)) {
499*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
500*4bdc9457SAndroid Build Coastguard Worker return;
501*4bdc9457SAndroid Build Coastguard Worker }
502*4bdc9457SAndroid Build Coastguard Worker
503*4bdc9457SAndroid Build Coastguard Worker emit32(0x0D40E000 | q(xs.vt1) | size(xs.vt1) | rn(xn.base) | xs.vt1.code);
504*4bdc9457SAndroid Build Coastguard Worker }
505*4bdc9457SAndroid Build Coastguard Worker
ldp(DRegister dt1,DRegister dt2,MemOperand xn)506*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldp(DRegister dt1, DRegister dt2, MemOperand xn) {
507*4bdc9457SAndroid Build Coastguard Worker if (!imm7_offset_valid(xn.offset, dt1)) {
508*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
509*4bdc9457SAndroid Build Coastguard Worker return;
510*4bdc9457SAndroid Build Coastguard Worker }
511*4bdc9457SAndroid Build Coastguard Worker
512*4bdc9457SAndroid Build Coastguard Worker const uint32_t offset = (xn.offset >> 3) & kImm7Mask;
513*4bdc9457SAndroid Build Coastguard Worker emit32(0x6C400000 | postindex(xn) | wb(xn) | offset << 15 | rt2(dt2) | rn(xn.base) | rt(dt1));
514*4bdc9457SAndroid Build Coastguard Worker }
515*4bdc9457SAndroid Build Coastguard Worker
ldp(DRegister dt1,DRegister dt2,MemOperand xn,int32_t imm)516*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldp(DRegister dt1, DRegister dt2, MemOperand xn, int32_t imm) {
517*4bdc9457SAndroid Build Coastguard Worker return ldp(dt1, dt2, {xn.base, imm, AddressingMode::kPostIndex});
518*4bdc9457SAndroid Build Coastguard Worker }
519*4bdc9457SAndroid Build Coastguard Worker
ldp(QRegister qt1,QRegister qt2,MemOperand xn,int32_t imm)520*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldp(QRegister qt1, QRegister qt2, MemOperand xn, int32_t imm) {
521*4bdc9457SAndroid Build Coastguard Worker if (!imm7_offset_valid(imm, qt1)) {
522*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
523*4bdc9457SAndroid Build Coastguard Worker return;
524*4bdc9457SAndroid Build Coastguard Worker }
525*4bdc9457SAndroid Build Coastguard Worker const uint32_t offset = (imm >> 4) & kImm7Mask;
526*4bdc9457SAndroid Build Coastguard Worker
527*4bdc9457SAndroid Build Coastguard Worker emit32(0xACC00000 | offset << 15 | rt2(qt2) | rn(xn.base) | qt1.code);
528*4bdc9457SAndroid Build Coastguard Worker }
529*4bdc9457SAndroid Build Coastguard Worker
ldr(DRegister dt,MemOperand xn,int32_t imm)530*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(DRegister dt, MemOperand xn, int32_t imm) {
531*4bdc9457SAndroid Build Coastguard Worker return ldr(/*size=*/3, /*opc=*/1, xn, imm, dt.code);
532*4bdc9457SAndroid Build Coastguard Worker }
533*4bdc9457SAndroid Build Coastguard Worker
ldr(QRegister qt,MemOperand xn,int32_t imm)534*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(QRegister qt, MemOperand xn, int32_t imm) {
535*4bdc9457SAndroid Build Coastguard Worker return ldr(/*size=*/0, /*opc=*/3, xn, imm, qt.code);
536*4bdc9457SAndroid Build Coastguard Worker }
537*4bdc9457SAndroid Build Coastguard Worker
ldr(SRegister st,MemOperand xn,int32_t imm)538*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(SRegister st, MemOperand xn, int32_t imm) {
539*4bdc9457SAndroid Build Coastguard Worker return ldr(/*size=*/2, /*opc=*/1, xn, imm, st.code);
540*4bdc9457SAndroid Build Coastguard Worker }
541*4bdc9457SAndroid Build Coastguard Worker
mov(VRegister vd,VRegister vn)542*4bdc9457SAndroid Build Coastguard Worker void Assembler::mov(VRegister vd, VRegister vn) {
543*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vd, vn)) {
544*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
545*4bdc9457SAndroid Build Coastguard Worker return;
546*4bdc9457SAndroid Build Coastguard Worker }
547*4bdc9457SAndroid Build Coastguard Worker emit32(0x0EA01C00 | q(vd) | rm(vn) | rn(vn) | rd(vd));
548*4bdc9457SAndroid Build Coastguard Worker }
549*4bdc9457SAndroid Build Coastguard Worker
movi(VRegister vd,uint8_t imm)550*4bdc9457SAndroid Build Coastguard Worker void Assembler::movi(VRegister vd, uint8_t imm) {
551*4bdc9457SAndroid Build Coastguard Worker if (imm != 0) {
552*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kUnimplemented;
553*4bdc9457SAndroid Build Coastguard Worker return;
554*4bdc9457SAndroid Build Coastguard Worker }
555*4bdc9457SAndroid Build Coastguard Worker
556*4bdc9457SAndroid Build Coastguard Worker uint32_t cmode = 0;
557*4bdc9457SAndroid Build Coastguard Worker switch (vd.size) {
558*4bdc9457SAndroid Build Coastguard Worker case 0:
559*4bdc9457SAndroid Build Coastguard Worker cmode = 0xE;
560*4bdc9457SAndroid Build Coastguard Worker break;
561*4bdc9457SAndroid Build Coastguard Worker case 1:
562*4bdc9457SAndroid Build Coastguard Worker cmode = 0x8;
563*4bdc9457SAndroid Build Coastguard Worker break;
564*4bdc9457SAndroid Build Coastguard Worker case 2:
565*4bdc9457SAndroid Build Coastguard Worker cmode = 0x0;
566*4bdc9457SAndroid Build Coastguard Worker break;
567*4bdc9457SAndroid Build Coastguard Worker default:
568*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kUnimplemented;
569*4bdc9457SAndroid Build Coastguard Worker return;
570*4bdc9457SAndroid Build Coastguard Worker }
571*4bdc9457SAndroid Build Coastguard Worker
572*4bdc9457SAndroid Build Coastguard Worker emit32(0x0F000400 | q(vd) | cmode << 12 | vd.code);
573*4bdc9457SAndroid Build Coastguard Worker }
574*4bdc9457SAndroid Build Coastguard Worker
st1(VRegisterList vs,MemOperand xn,XRegister xm)575*4bdc9457SAndroid Build Coastguard Worker void Assembler::st1(VRegisterList vs, MemOperand xn, XRegister xm) {
576*4bdc9457SAndroid Build Coastguard Worker if (!is_same_shape(vs) || !is_consecutive(vs)) {
577*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
578*4bdc9457SAndroid Build Coastguard Worker return;
579*4bdc9457SAndroid Build Coastguard Worker }
580*4bdc9457SAndroid Build Coastguard Worker
581*4bdc9457SAndroid Build Coastguard Worker VRegister vt = vs.vt1;
582*4bdc9457SAndroid Build Coastguard Worker
583*4bdc9457SAndroid Build Coastguard Worker const uint8_t opcode = load_store_opcode(vs.length);
584*4bdc9457SAndroid Build Coastguard Worker emit32(0x0C800000 | q(vt) | rm(xm) | opcode << 12 | size(vt) | rn(xn.base) | rt(vt));
585*4bdc9457SAndroid Build Coastguard Worker }
586*4bdc9457SAndroid Build Coastguard Worker
stp(DRegister dt1,DRegister dt2,MemOperand xn)587*4bdc9457SAndroid Build Coastguard Worker void Assembler::stp(DRegister dt1, DRegister dt2, MemOperand xn) {
588*4bdc9457SAndroid Build Coastguard Worker if (!imm7_offset_valid(xn.offset, dt1)) {
589*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
590*4bdc9457SAndroid Build Coastguard Worker return;
591*4bdc9457SAndroid Build Coastguard Worker }
592*4bdc9457SAndroid Build Coastguard Worker
593*4bdc9457SAndroid Build Coastguard Worker const uint32_t offset = (xn.offset >> 3) & kImm7Mask;
594*4bdc9457SAndroid Build Coastguard Worker emit32(0x6D000000 | wb(xn) | offset << 15 | rt2(dt2) | rn(xn.base) | rt(dt1));
595*4bdc9457SAndroid Build Coastguard Worker }
596*4bdc9457SAndroid Build Coastguard Worker
stp(QRegister qt1,QRegister qt2,MemOperand xn)597*4bdc9457SAndroid Build Coastguard Worker void Assembler::stp(QRegister qt1, QRegister qt2, MemOperand xn) {
598*4bdc9457SAndroid Build Coastguard Worker if (!imm7_offset_valid(xn.offset, qt1)) {
599*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
600*4bdc9457SAndroid Build Coastguard Worker return;
601*4bdc9457SAndroid Build Coastguard Worker }
602*4bdc9457SAndroid Build Coastguard Worker
603*4bdc9457SAndroid Build Coastguard Worker const uint32_t offset = (xn.offset >> 4) & kImm7Mask;
604*4bdc9457SAndroid Build Coastguard Worker emit32(0xAD000000 | wb(xn) | offset << 15 | rt2(qt2) | rn(xn.base) | rt(qt1));
605*4bdc9457SAndroid Build Coastguard Worker }
606*4bdc9457SAndroid Build Coastguard Worker
stp(QRegister qt1,QRegister qt2,MemOperand xn,int32_t imm)607*4bdc9457SAndroid Build Coastguard Worker void Assembler::stp(QRegister qt1, QRegister qt2, MemOperand xn, int32_t imm) {
608*4bdc9457SAndroid Build Coastguard Worker if (!imm7_offset_valid(imm, qt1)) {
609*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
610*4bdc9457SAndroid Build Coastguard Worker return;
611*4bdc9457SAndroid Build Coastguard Worker }
612*4bdc9457SAndroid Build Coastguard Worker
613*4bdc9457SAndroid Build Coastguard Worker const uint32_t offset = (imm >> 4) & kImm7Mask;
614*4bdc9457SAndroid Build Coastguard Worker emit32(0xAC800000 | offset << 15 | rt2(qt2) | rn(xn.base) | rt(qt1));
615*4bdc9457SAndroid Build Coastguard Worker }
616*4bdc9457SAndroid Build Coastguard Worker
str(DRegister dt,MemOperand xn,int32_t imm)617*4bdc9457SAndroid Build Coastguard Worker void Assembler::str(DRegister dt, MemOperand xn, int32_t imm) {
618*4bdc9457SAndroid Build Coastguard Worker return str(/*size=*/3, /*opc=*/0, xn, imm, dt.code);
619*4bdc9457SAndroid Build Coastguard Worker }
620*4bdc9457SAndroid Build Coastguard Worker
str(QRegister qt,MemOperand xn,int32_t imm)621*4bdc9457SAndroid Build Coastguard Worker void Assembler::str(QRegister qt, MemOperand xn, int32_t imm) {
622*4bdc9457SAndroid Build Coastguard Worker return str(/*size=*/0, /*opc=*/2, xn, imm, qt.code);
623*4bdc9457SAndroid Build Coastguard Worker }
624*4bdc9457SAndroid Build Coastguard Worker
str(SRegister st,MemOperand xn)625*4bdc9457SAndroid Build Coastguard Worker void Assembler::str(SRegister st, MemOperand xn) {
626*4bdc9457SAndroid Build Coastguard Worker const int32_t imm = xn.offset;
627*4bdc9457SAndroid Build Coastguard Worker if (imm < 0 || imm > (kUint12Max << 2) || (imm & 0x3) != 0) {
628*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
629*4bdc9457SAndroid Build Coastguard Worker return;
630*4bdc9457SAndroid Build Coastguard Worker }
631*4bdc9457SAndroid Build Coastguard Worker
632*4bdc9457SAndroid Build Coastguard Worker emit32(0xBD000000 | imm >> 2 << 10 | rn(xn.base) | rt(st));
633*4bdc9457SAndroid Build Coastguard Worker }
634*4bdc9457SAndroid Build Coastguard Worker
str(SRegister st,MemOperand xn,int32_t imm)635*4bdc9457SAndroid Build Coastguard Worker void Assembler::str(SRegister st, MemOperand xn, int32_t imm) {
636*4bdc9457SAndroid Build Coastguard Worker return str(/*size=*/2, /*opc=*/0, xn, imm, st.code);
637*4bdc9457SAndroid Build Coastguard Worker }
638*4bdc9457SAndroid Build Coastguard Worker
align(uint8_t n,AlignInstruction instr)639*4bdc9457SAndroid Build Coastguard Worker void Assembler::align(uint8_t n, AlignInstruction instr) {
640*4bdc9457SAndroid Build Coastguard Worker if (!is_po2(n) || (n % kInstructionSizeInBytes != 0)) {
641*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
642*4bdc9457SAndroid Build Coastguard Worker return;
643*4bdc9457SAndroid Build Coastguard Worker }
644*4bdc9457SAndroid Build Coastguard Worker
645*4bdc9457SAndroid Build Coastguard Worker uintptr_t cursor = reinterpret_cast<uintptr_t>(cursor_);
646*4bdc9457SAndroid Build Coastguard Worker const uintptr_t target = round_up_po2(cursor, n);
647*4bdc9457SAndroid Build Coastguard Worker while (cursor < target) {
648*4bdc9457SAndroid Build Coastguard Worker switch (instr) {
649*4bdc9457SAndroid Build Coastguard Worker case AlignInstruction::kHlt:
650*4bdc9457SAndroid Build Coastguard Worker hlt();
651*4bdc9457SAndroid Build Coastguard Worker break;
652*4bdc9457SAndroid Build Coastguard Worker case AlignInstruction::kNop:
653*4bdc9457SAndroid Build Coastguard Worker nop();
654*4bdc9457SAndroid Build Coastguard Worker break;
655*4bdc9457SAndroid Build Coastguard Worker default:
656*4bdc9457SAndroid Build Coastguard Worker XNN_UNREACHABLE;
657*4bdc9457SAndroid Build Coastguard Worker }
658*4bdc9457SAndroid Build Coastguard Worker cursor += kInstructionSizeInBytes;
659*4bdc9457SAndroid Build Coastguard Worker }
660*4bdc9457SAndroid Build Coastguard Worker }
661*4bdc9457SAndroid Build Coastguard Worker
bind(Label & l)662*4bdc9457SAndroid Build Coastguard Worker void Assembler::bind(Label& l) {
663*4bdc9457SAndroid Build Coastguard Worker if (error_ != Error::kNoError) {
664*4bdc9457SAndroid Build Coastguard Worker return;
665*4bdc9457SAndroid Build Coastguard Worker }
666*4bdc9457SAndroid Build Coastguard Worker
667*4bdc9457SAndroid Build Coastguard Worker if (l.bound) {
668*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kLabelAlreadyBound;
669*4bdc9457SAndroid Build Coastguard Worker return;
670*4bdc9457SAndroid Build Coastguard Worker }
671*4bdc9457SAndroid Build Coastguard Worker
672*4bdc9457SAndroid Build Coastguard Worker l.bound = true;
673*4bdc9457SAndroid Build Coastguard Worker l.offset = cursor_;
674*4bdc9457SAndroid Build Coastguard Worker
675*4bdc9457SAndroid Build Coastguard Worker // Patch all users.
676*4bdc9457SAndroid Build Coastguard Worker for (size_t i = 0; i < l.num_users; i++) {
677*4bdc9457SAndroid Build Coastguard Worker byte* user = l.users[i];
678*4bdc9457SAndroid Build Coastguard Worker const ptrdiff_t offset = l.offset - user;
679*4bdc9457SAndroid Build Coastguard Worker uint32_t* instr = reinterpret_cast<uint32_t*>(user);
680*4bdc9457SAndroid Build Coastguard Worker
681*4bdc9457SAndroid Build Coastguard Worker const BranchType bt = instruction_branch_type(*instr);
682*4bdc9457SAndroid Build Coastguard Worker if (!branch_offset_valid(offset, bt)) {
683*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kLabelOffsetOutOfBounds;
684*4bdc9457SAndroid Build Coastguard Worker return;
685*4bdc9457SAndroid Build Coastguard Worker }
686*4bdc9457SAndroid Build Coastguard Worker
687*4bdc9457SAndroid Build Coastguard Worker *instr |= branch_imm(offset, bt);
688*4bdc9457SAndroid Build Coastguard Worker }
689*4bdc9457SAndroid Build Coastguard Worker }
690*4bdc9457SAndroid Build Coastguard Worker
b(Condition c,Label & l)691*4bdc9457SAndroid Build Coastguard Worker void Assembler::b(Condition c, Label& l) {
692*4bdc9457SAndroid Build Coastguard Worker return branch_to_label(0x54000000 | c, BranchType::kConditional, l);
693*4bdc9457SAndroid Build Coastguard Worker }
694*4bdc9457SAndroid Build Coastguard Worker
branch_to_label(uint32_t opcode,BranchType bt,Label & l)695*4bdc9457SAndroid Build Coastguard Worker void Assembler::branch_to_label(uint32_t opcode, BranchType bt, Label& l) {
696*4bdc9457SAndroid Build Coastguard Worker if (l.bound) {
697*4bdc9457SAndroid Build Coastguard Worker const ptrdiff_t offset = l.offset - cursor_;
698*4bdc9457SAndroid Build Coastguard Worker if (!branch_offset_valid(offset, bt)) {
699*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kLabelOffsetOutOfBounds;
700*4bdc9457SAndroid Build Coastguard Worker return;
701*4bdc9457SAndroid Build Coastguard Worker }
702*4bdc9457SAndroid Build Coastguard Worker emit32(opcode | branch_imm(offset, bt));
703*4bdc9457SAndroid Build Coastguard Worker } else {
704*4bdc9457SAndroid Build Coastguard Worker if (!l.add_use(cursor_)) {
705*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kLabelHasTooManyUsers;
706*4bdc9457SAndroid Build Coastguard Worker return;
707*4bdc9457SAndroid Build Coastguard Worker }
708*4bdc9457SAndroid Build Coastguard Worker emit32(opcode);
709*4bdc9457SAndroid Build Coastguard Worker }
710*4bdc9457SAndroid Build Coastguard Worker }
711*4bdc9457SAndroid Build Coastguard Worker
ldr(uint32_t size,uint32_t opc,MemOperand xn,int32_t imm,uint8_t rt_code)712*4bdc9457SAndroid Build Coastguard Worker void Assembler::ldr(uint32_t size, uint32_t opc, MemOperand xn, int32_t imm, uint8_t rt_code) {
713*4bdc9457SAndroid Build Coastguard Worker if (xn.mode != AddressingMode::kOffset || xn.offset != 0 || imm < kInt9Min || imm > kInt9Max) {
714*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
715*4bdc9457SAndroid Build Coastguard Worker return;
716*4bdc9457SAndroid Build Coastguard Worker }
717*4bdc9457SAndroid Build Coastguard Worker
718*4bdc9457SAndroid Build Coastguard Worker emit32(0x3C400400 | size << 30 | opc << 22 | imm9(imm) | rn(xn.base) | rt_code);
719*4bdc9457SAndroid Build Coastguard Worker }
720*4bdc9457SAndroid Build Coastguard Worker
str(uint32_t size,uint32_t opc,MemOperand xn,int32_t imm,uint8_t rt_code)721*4bdc9457SAndroid Build Coastguard Worker void Assembler::str(uint32_t size, uint32_t opc, MemOperand xn, int32_t imm, uint8_t rt_code) {
722*4bdc9457SAndroid Build Coastguard Worker if (imm < kInt9Min || imm > kInt9Max) {
723*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
724*4bdc9457SAndroid Build Coastguard Worker return;
725*4bdc9457SAndroid Build Coastguard Worker }
726*4bdc9457SAndroid Build Coastguard Worker
727*4bdc9457SAndroid Build Coastguard Worker emit32(0x3C000400 | size << 30 | opc << 22 | imm9(imm) | rn(xn.base) | rt_code);
728*4bdc9457SAndroid Build Coastguard Worker }
729*4bdc9457SAndroid Build Coastguard Worker
tb_helper(uint32_t op,XRegister xd,uint8_t bit,Label & l)730*4bdc9457SAndroid Build Coastguard Worker void Assembler::tb_helper(uint32_t op, XRegister xd, uint8_t bit, Label& l) {
731*4bdc9457SAndroid Build Coastguard Worker if (bit > 63) {
732*4bdc9457SAndroid Build Coastguard Worker error_ = Error::kInvalidOperand;
733*4bdc9457SAndroid Build Coastguard Worker return;
734*4bdc9457SAndroid Build Coastguard Worker }
735*4bdc9457SAndroid Build Coastguard Worker
736*4bdc9457SAndroid Build Coastguard Worker const uint32_t bit_pos = (bit & 0x20) >> 5 << 31 | (bit & 0x1F) << 19;
737*4bdc9457SAndroid Build Coastguard Worker return branch_to_label(op | bit_pos | xd.code, BranchType::kTbxz, l);
738*4bdc9457SAndroid Build Coastguard Worker }
739*4bdc9457SAndroid Build Coastguard Worker
740*4bdc9457SAndroid Build Coastguard Worker } // namespace aarch64
741*4bdc9457SAndroid Build Coastguard Worker } // namespace xnnpack
742