1 //===- subzero/src/IceAssemblerARM32.cpp - Assembler for ARM32 --*- C++ -*-===//
2 //
3 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
4 // for details. All rights reserved. Use of this source code is governed by a
5 // BSD-style license that can be found in the LICENSE file.
6 //
7 // Modified by the Subzero authors.
8 //
9 //===----------------------------------------------------------------------===//
10 //
11 // The Subzero Code Generator
12 //
13 // This file is distributed under the University of Illinois Open Source
14 // License. See LICENSE.TXT for details.
15 //
16 //===----------------------------------------------------------------------===//
17 ///
18 /// \file
19 /// \brief Implements the Assembler class for ARM32.
20 ///
21 //===----------------------------------------------------------------------===//
22
23 #include "IceAssemblerARM32.h"
24 #include "IceCfgNode.h"
25 #include "IceUtils.h"
26
27 namespace {
28
29 using namespace Ice;
30 using namespace Ice::ARM32;
31
32 using WordType = uint32_t;
33 static constexpr IValueT kWordSize = sizeof(WordType);
34
35 // The following define individual bits.
36 static constexpr IValueT B0 = 1;
37 static constexpr IValueT B1 = 1 << 1;
38 static constexpr IValueT B2 = 1 << 2;
39 static constexpr IValueT B3 = 1 << 3;
40 static constexpr IValueT B4 = 1 << 4;
41 static constexpr IValueT B5 = 1 << 5;
42 static constexpr IValueT B6 = 1 << 6;
43 static constexpr IValueT B7 = 1 << 7;
44 static constexpr IValueT B8 = 1 << 8;
45 static constexpr IValueT B9 = 1 << 9;
46 static constexpr IValueT B10 = 1 << 10;
47 static constexpr IValueT B11 = 1 << 11;
48 static constexpr IValueT B12 = 1 << 12;
49 static constexpr IValueT B13 = 1 << 13;
50 static constexpr IValueT B14 = 1 << 14;
51 static constexpr IValueT B15 = 1 << 15;
52 static constexpr IValueT B16 = 1 << 16;
53 static constexpr IValueT B17 = 1 << 17;
54 static constexpr IValueT B18 = 1 << 18;
55 static constexpr IValueT B19 = 1 << 19;
56 static constexpr IValueT B20 = 1 << 20;
57 static constexpr IValueT B21 = 1 << 21;
58 static constexpr IValueT B22 = 1 << 22;
59 static constexpr IValueT B23 = 1 << 23;
60 static constexpr IValueT B24 = 1 << 24;
61 static constexpr IValueT B25 = 1 << 25;
62 static constexpr IValueT B26 = 1 << 26;
63 static constexpr IValueT B27 = 1 << 27;
64
65 // Constants used for the decoding or encoding of the individual fields of
66 // instructions. Based on ARM section A5.1.
67 static constexpr IValueT L = 1 << 20; // load (or store)
68 static constexpr IValueT W = 1 << 21; // writeback base register
69 // (or leave unchanged)
70 static constexpr IValueT B = 1 << 22; // unsigned byte (or word)
71 static constexpr IValueT U = 1 << 23; // positive (or negative)
72 // offset/index
73 static constexpr IValueT P = 1 << 24; // offset/pre-indexed
74 // addressing (or
75 // post-indexed addressing)
76
77 static constexpr IValueT kConditionShift = 28;
78 static constexpr IValueT kLinkShift = 24;
79 static constexpr IValueT kOpcodeShift = 21;
80 static constexpr IValueT kRdShift = 12;
81 static constexpr IValueT kRmShift = 0;
82 static constexpr IValueT kRnShift = 16;
83 static constexpr IValueT kRsShift = 8;
84 static constexpr IValueT kSShift = 20;
85 static constexpr IValueT kTypeShift = 25;
86
87 // Immediate instruction fields encoding.
88 static constexpr IValueT kImmed8Bits = 8;
89 static constexpr IValueT kImmed8Shift = 0;
90 static constexpr IValueT kRotateBits = 4;
91 static constexpr IValueT kRotateShift = 8;
92
93 // Shift instruction register fields encodings.
94 static constexpr IValueT kShiftImmShift = 7;
95 static constexpr IValueT kShiftImmBits = 5;
96 static constexpr IValueT kShiftShift = 5;
97 static constexpr IValueT kImmed12Bits = 12;
98 static constexpr IValueT kImm12Shift = 0;
99
100 // Rotation instructions (uxtb etc.).
101 static constexpr IValueT kRotationShift = 10;
102
103 // MemEx instructions.
104 static constexpr IValueT kMemExOpcodeShift = 20;
105
106 // Div instruction register field encodings.
107 static constexpr IValueT kDivRdShift = 16;
108 static constexpr IValueT kDivRmShift = 8;
109 static constexpr IValueT kDivRnShift = 0;
110
111 // Type of instruction encoding (bits 25-27). See ARM section A5.1
112 static constexpr IValueT kInstTypeDataRegister = 0; // i.e. 000
113 static constexpr IValueT kInstTypeDataRegShift = 0; // i.e. 000
114 static constexpr IValueT kInstTypeDataImmediate = 1; // i.e. 001
115 static constexpr IValueT kInstTypeMemImmediate = 2; // i.e. 010
116 static constexpr IValueT kInstTypeRegisterShift = 3; // i.e. 011
117
118 // Limit on number of registers in a vpush/vpop.
119 static constexpr SizeT VpushVpopMaxConsecRegs = 16;
120
121 // Offset modifier to current PC for next instruction. The offset is off by 8
122 // due to the way the ARM CPUs read PC.
123 static constexpr IOffsetT kPCReadOffset = 8;
124
125 // Mask to pull out PC offset from branch (b) instruction.
126 static constexpr int kBranchOffsetBits = 24;
127 static constexpr IOffsetT kBranchOffsetMask = 0x00ffffff;
128
encodeBool(bool B)129 IValueT encodeBool(bool B) { return B ? 1 : 0; }
130
encodeRotation(ARM32::AssemblerARM32::RotationValue Value)131 IValueT encodeRotation(ARM32::AssemblerARM32::RotationValue Value) {
132 return static_cast<IValueT>(Value);
133 }
134
encodeGPRRegister(RegARM32::GPRRegister Rn)135 IValueT encodeGPRRegister(RegARM32::GPRRegister Rn) {
136 return static_cast<IValueT>(Rn);
137 }
138
decodeGPRRegister(IValueT R)139 RegARM32::GPRRegister decodeGPRRegister(IValueT R) {
140 return static_cast<RegARM32::GPRRegister>(R);
141 }
142
encodeCondition(CondARM32::Cond Cond)143 IValueT encodeCondition(CondARM32::Cond Cond) {
144 return static_cast<IValueT>(Cond);
145 }
146
encodeShift(OperandARM32::ShiftKind Shift)147 IValueT encodeShift(OperandARM32::ShiftKind Shift) {
148 // Follows encoding in ARM section A8.4.1 "Constant shifts".
149 switch (Shift) {
150 case OperandARM32::kNoShift:
151 case OperandARM32::LSL:
152 return 0; // 0b00
153 case OperandARM32::LSR:
154 return 1; // 0b01
155 case OperandARM32::ASR:
156 return 2; // 0b10
157 case OperandARM32::ROR:
158 case OperandARM32::RRX:
159 return 3; // 0b11
160 }
161 llvm::report_fatal_error("Unknown Shift value");
162 return 0;
163 }
164
165 // Returns the bits in the corresponding masked value.
mask(IValueT Value,IValueT Shift,IValueT Bits)166 IValueT mask(IValueT Value, IValueT Shift, IValueT Bits) {
167 return (Value >> Shift) & ((1 << Bits) - 1);
168 }
169
170 // Extract out a Bit in Value.
isBitSet(IValueT Bit,IValueT Value)171 bool isBitSet(IValueT Bit, IValueT Value) { return (Value & Bit) == Bit; }
172
173 // Returns the GPR register at given Shift in Value.
getGPRReg(IValueT Shift,IValueT Value)174 RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) {
175 return decodeGPRRegister((Value >> Shift) & 0xF);
176 }
177
getEncodedGPRegNum(const Variable * Var)178 IValueT getEncodedGPRegNum(const Variable *Var) {
179 assert(Var->hasReg());
180 const auto Reg = Var->getRegNum();
181 return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg)
182 : RegARM32::getEncodedGPR(Reg);
183 }
184
getEncodedSRegNum(const Variable * Var)185 IValueT getEncodedSRegNum(const Variable *Var) {
186 assert(Var->hasReg());
187 return RegARM32::getEncodedSReg(Var->getRegNum());
188 }
189
getEncodedDRegNum(const Variable * Var)190 IValueT getEncodedDRegNum(const Variable *Var) {
191 return RegARM32::getEncodedDReg(Var->getRegNum());
192 }
193
getEncodedQRegNum(const Variable * Var)194 IValueT getEncodedQRegNum(const Variable *Var) {
195 return RegARM32::getEncodedQReg(Var->getRegNum());
196 }
197
mapQRegToDReg(IValueT EncodedQReg)198 IValueT mapQRegToDReg(IValueT EncodedQReg) {
199 IValueT DReg = EncodedQReg << 1;
200 assert(DReg < RegARM32::getNumDRegs());
201 return DReg;
202 }
203
mapQRegToSReg(IValueT EncodedQReg)204 IValueT mapQRegToSReg(IValueT EncodedQReg) {
205 IValueT SReg = EncodedQReg << 2;
206 assert(SReg < RegARM32::getNumSRegs());
207 return SReg;
208 }
209
getYInRegXXXXY(IValueT RegXXXXY)210 IValueT getYInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY & 0x1; }
211
getXXXXInRegXXXXY(IValueT RegXXXXY)212 IValueT getXXXXInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY >> 1; }
213
getYInRegYXXXX(IValueT RegYXXXX)214 IValueT getYInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX >> 4; }
215
getXXXXInRegYXXXX(IValueT RegYXXXX)216 IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; }
217
218 // Figures out Op/Cmode values for given Value. Returns true if able to encode.
encodeAdvSIMDExpandImm(IValueT Value,Type ElmtTy,IValueT & Op,IValueT & Cmode,IValueT & Imm8)219 bool encodeAdvSIMDExpandImm(IValueT Value, Type ElmtTy, IValueT &Op,
220 IValueT &Cmode, IValueT &Imm8) {
221 // TODO(kschimpf): Handle other shifted 8-bit values.
222 constexpr IValueT Imm8Mask = 0xFF;
223 if ((Value & IValueT(~Imm8Mask)) != 0)
224 return false;
225 Imm8 = Value;
226 switch (ElmtTy) {
227 case IceType_i8:
228 Op = 0;
229 Cmode = 14; // 0b1110
230 return true;
231 case IceType_i16:
232 Op = 0;
233 Cmode = 8; // 0b1000
234 return true;
235 case IceType_i32:
236 Op = 0;
237 Cmode = 0; // 0b0000
238 return true;
239 default:
240 return false;
241 }
242 }
243
244 // Defines layouts of an operand representing a (register) memory address,
245 // possibly modified by an immediate value.
246 enum EncodedImmAddress {
247 // Address modified by a rotated immediate 8-bit value.
248 RotatedImm8Address,
249
250 // Alternate encoding for RotatedImm8Address, where the offset is divided by 4
251 // before encoding.
252 RotatedImm8Div4Address,
253
254 // Address modified by an immediate 12-bit value.
255 Imm12Address,
256
257 // Alternate encoding 3, for an address modified by a rotated immediate 8-bit
258 // value.
259 RotatedImm8Enc3Address,
260
261 // Encoding where no immediate offset is used.
262 NoImmOffsetAddress
263 };
264
265 // The way an operand is encoded into a sequence of bits in functions
266 // encodeOperand and encodeAddress below.
267 enum EncodedOperand {
268 // Unable to encode, value left undefined.
269 CantEncode = 0,
270
271 // Value is register found.
272 EncodedAsRegister,
273
274 // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8
275 // value.
276 EncodedAsRotatedImm8,
277
278 // EncodedAsImmRegOffset is a memory operand that can take three forms, based
279 // on type EncodedImmAddress:
280 //
281 // ***** RotatedImm8Address *****
282 //
283 // Value=0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
284 // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to
285 // Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value.
286 //
287 // ***** RotatedImm8Div4Address *****
288 //
289 // Value=00000000pu0w0nnnn0000iiii0000jjjj where nnnn=Rn, iiiijjjj=Imm8, p=1
290 // if pre-indexed addressing, u=1 if offset positive, and w=1 if writeback to
291 // Rn.
292 //
293 // ***** Imm12Address *****
294 //
295 // Value=0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
296 // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to
297 // Rn should be used, and iiiiiiiiiiii defines the immediate 12-bit value.
298 //
299 // ***** NoImmOffsetAddress *****
300 //
301 // Value=000000001000nnnn0000000000000000 where nnnn=Rn.
302 EncodedAsImmRegOffset,
303
304 // Value=0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn,
305 // mmmm is the index register Rm, iiiii is the shift amount, ss is the shift
306 // kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if
307 // writeback to Rn.
308 EncodedAsShiftRotateImm5,
309
310 // Value=000000000000000000000iiiii0000000 where iiii defines the Imm5 value
311 // to shift.
312 EncodedAsShiftImm5,
313
314 // Value=iiiiiss0mmmm where mmmm is the register to rotate, ss is the shift
315 // kind, and iiiii is the shift amount.
316 EncodedAsShiftedRegister,
317
318 // Value=ssss0tt1mmmm where mmmm=Rm, tt is an encoded ShiftKind, and ssss=Rms.
319 EncodedAsRegShiftReg,
320
321 // Value is 32bit integer constant.
322 EncodedAsConstI32
323 };
324
325 // Sets Encoding to a rotated Imm8 encoding of Value, if possible.
encodeRotatedImm8(IValueT RotateAmt,IValueT Immed8)326 IValueT encodeRotatedImm8(IValueT RotateAmt, IValueT Immed8) {
327 assert(RotateAmt < (1 << kRotateBits));
328 assert(Immed8 < (1 << kImmed8Bits));
329 return (RotateAmt << kRotateShift) | (Immed8 << kImmed8Shift);
330 }
331
332 // Encodes iiiiitt0mmmm for data-processing (2nd) operands where iiiii=Imm5,
333 // tt=Shift, and mmmm=Rm.
encodeShiftRotateImm5(IValueT Rm,OperandARM32::ShiftKind Shift,IOffsetT imm5)334 IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift,
335 IOffsetT imm5) {
336 (void)kShiftImmBits;
337 assert(imm5 < (1 << kShiftImmBits));
338 return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm;
339 }
340
341 // Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and
342 // tt=Shift.
encodeShiftRotateReg(IValueT Rm,OperandARM32::ShiftKind Shift,IValueT Rs)343 IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift,
344 IValueT Rs) {
345 return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 |
346 (Rm << kRmShift);
347 }
348
349 // Defines the set of registers expected in an operand.
350 enum RegSetWanted { WantGPRegs, WantSRegs, WantDRegs, WantQRegs };
351
encodeOperand(const Operand * Opnd,IValueT & Value,RegSetWanted WantedRegSet)352 EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value,
353 RegSetWanted WantedRegSet) {
354 Value = 0; // Make sure initialized.
355 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
356 if (Var->hasReg()) {
357 switch (WantedRegSet) {
358 case WantGPRegs:
359 Value = getEncodedGPRegNum(Var);
360 break;
361 case WantSRegs:
362 Value = getEncodedSRegNum(Var);
363 break;
364 case WantDRegs:
365 Value = getEncodedDRegNum(Var);
366 break;
367 case WantQRegs:
368 Value = getEncodedQRegNum(Var);
369 break;
370 }
371 return EncodedAsRegister;
372 }
373 return CantEncode;
374 }
375 if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) {
376 const IValueT Immed8 = FlexImm->getImm();
377 const IValueT Rotate = FlexImm->getRotateAmt();
378 if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits))))
379 return CantEncode;
380 Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift);
381 return EncodedAsRotatedImm8;
382 }
383 if (const auto *Const = llvm::dyn_cast<ConstantInteger32>(Opnd)) {
384 Value = Const->getValue();
385 return EncodedAsConstI32;
386 }
387 if (const auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Opnd)) {
388 Operand *Amt = FlexReg->getShiftAmt();
389 IValueT Rm;
390 if (encodeOperand(FlexReg->getReg(), Rm, WantGPRegs) != EncodedAsRegister)
391 return CantEncode;
392 if (const auto *Var = llvm::dyn_cast<Variable>(Amt)) {
393 IValueT Rs;
394 if (encodeOperand(Var, Rs, WantGPRegs) != EncodedAsRegister)
395 return CantEncode;
396 Value = encodeShiftRotateReg(Rm, FlexReg->getShiftOp(), Rs);
397 return EncodedAsRegShiftReg;
398 }
399 // If reached, the amount is a shifted amount by some 5-bit immediate.
400 uint32_t Imm5;
401 if (const auto *ShAmt = llvm::dyn_cast<OperandARM32ShAmtImm>(Amt)) {
402 Imm5 = ShAmt->getShAmtImm();
403 } else if (const auto *IntConst = llvm::dyn_cast<ConstantInteger32>(Amt)) {
404 int32_t Val = IntConst->getValue();
405 if (Val < 0)
406 return CantEncode;
407 Imm5 = static_cast<uint32_t>(Val);
408 } else
409 return CantEncode;
410 Value = encodeShiftRotateImm5(Rm, FlexReg->getShiftOp(), Imm5);
411 return EncodedAsShiftedRegister;
412 }
413 if (const auto *ShImm = llvm::dyn_cast<OperandARM32ShAmtImm>(Opnd)) {
414 const IValueT Immed5 = ShImm->getShAmtImm();
415 assert(Immed5 < (1 << kShiftImmBits));
416 Value = (Immed5 << kShiftImmShift);
417 return EncodedAsShiftImm5;
418 }
419 return CantEncode;
420 }
421
encodeImmRegOffset(IValueT Reg,IOffsetT Offset,OperandARM32Mem::AddrMode Mode,IOffsetT MaxOffset,IValueT OffsetShift)422 IValueT encodeImmRegOffset(IValueT Reg, IOffsetT Offset,
423 OperandARM32Mem::AddrMode Mode, IOffsetT MaxOffset,
424 IValueT OffsetShift) {
425 IValueT Value = Mode | (Reg << kRnShift);
426 if (Offset < 0) {
427 Offset = -Offset;
428 Value ^= U; // Flip U to adjust sign.
429 }
430 assert(Offset <= MaxOffset);
431 (void)MaxOffset;
432 return Value | (Offset >> OffsetShift);
433 }
434
435 // Encodes immediate register offset using encoding 3.
encodeImmRegOffsetEnc3(IValueT Rn,IOffsetT Imm8,OperandARM32Mem::AddrMode Mode)436 IValueT encodeImmRegOffsetEnc3(IValueT Rn, IOffsetT Imm8,
437 OperandARM32Mem::AddrMode Mode) {
438 IValueT Value = Mode | (Rn << kRnShift);
439 if (Imm8 < 0) {
440 Imm8 = -Imm8;
441 Value = (Value ^ U);
442 }
443 assert(Imm8 < (1 << 8));
444 Value = Value | B22 | ((Imm8 & 0xf0) << 4) | (Imm8 & 0x0f);
445 return Value;
446 }
447
encodeImmRegOffset(EncodedImmAddress ImmEncoding,IValueT Reg,IOffsetT Offset,OperandARM32Mem::AddrMode Mode)448 IValueT encodeImmRegOffset(EncodedImmAddress ImmEncoding, IValueT Reg,
449 IOffsetT Offset, OperandARM32Mem::AddrMode Mode) {
450 switch (ImmEncoding) {
451 case RotatedImm8Address: {
452 constexpr IOffsetT MaxOffset = (1 << 8) - 1;
453 constexpr IValueT NoRightShift = 0;
454 return encodeImmRegOffset(Reg, Offset, Mode, MaxOffset, NoRightShift);
455 }
456 case RotatedImm8Div4Address: {
457 assert((Offset & 0x3) == 0);
458 constexpr IOffsetT MaxOffset = (1 << 8) - 1;
459 constexpr IValueT RightShift2 = 2;
460 return encodeImmRegOffset(Reg, Offset, Mode, MaxOffset, RightShift2);
461 }
462 case Imm12Address: {
463 constexpr IOffsetT MaxOffset = (1 << 12) - 1;
464 constexpr IValueT NoRightShift = 0;
465 return encodeImmRegOffset(Reg, Offset, Mode, MaxOffset, NoRightShift);
466 }
467 case RotatedImm8Enc3Address:
468 return encodeImmRegOffsetEnc3(Reg, Offset, Mode);
469 case NoImmOffsetAddress: {
470 assert(Offset == 0);
471 assert(Mode == OperandARM32Mem::Offset);
472 return Reg << kRnShift;
473 }
474 }
475 llvm_unreachable("(silence g++ warning)");
476 }
477
478 // Encodes memory address Opnd, and encodes that information into Value, based
479 // on how ARM represents the address. Returns how the value was encoded.
encodeAddress(const Operand * Opnd,IValueT & Value,const AssemblerARM32::TargetInfo & TInfo,EncodedImmAddress ImmEncoding)480 EncodedOperand encodeAddress(const Operand *Opnd, IValueT &Value,
481 const AssemblerARM32::TargetInfo &TInfo,
482 EncodedImmAddress ImmEncoding) {
483 Value = 0; // Make sure initialized.
484 if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
485 // Should be a stack variable, with an offset.
486 if (Var->hasReg())
487 return CantEncode;
488 IOffsetT Offset = Var->getStackOffset();
489 if (!Utils::IsAbsoluteUint(12, Offset))
490 return CantEncode;
491 const auto BaseRegNum =
492 Var->hasReg() ? Var->getBaseRegNum() : TInfo.FrameOrStackReg;
493 Value = encodeImmRegOffset(ImmEncoding, BaseRegNum, Offset,
494 OperandARM32Mem::Offset);
495 return EncodedAsImmRegOffset;
496 }
497 if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) {
498 Variable *Var = Mem->getBase();
499 if (!Var->hasReg())
500 return CantEncode;
501 IValueT Rn = getEncodedGPRegNum(Var);
502 if (Mem->isRegReg()) {
503 const Variable *Index = Mem->getIndex();
504 if (Var == nullptr)
505 return CantEncode;
506 Value = (Rn << kRnShift) | Mem->getAddrMode() |
507 encodeShiftRotateImm5(getEncodedGPRegNum(Index),
508 Mem->getShiftOp(), Mem->getShiftAmt());
509 return EncodedAsShiftRotateImm5;
510 }
511 // Encoded as immediate register offset.
512 ConstantInteger32 *Offset = Mem->getOffset();
513 Value = encodeImmRegOffset(ImmEncoding, Rn, Offset->getValue(),
514 Mem->getAddrMode());
515 return EncodedAsImmRegOffset;
516 }
517 return CantEncode;
518 }
519
520 // Checks that Offset can fit in imm24 constant of branch (b) instruction.
assertCanEncodeBranchOffset(IOffsetT Offset)521 void assertCanEncodeBranchOffset(IOffsetT Offset) {
522 (void)Offset;
523 (void)kBranchOffsetBits;
524 assert(Utils::IsAligned(Offset, 4) &&
525 Utils::IsInt(kBranchOffsetBits, Offset >> 2));
526 }
527
encodeBranchOffset(IOffsetT Offset,IValueT Inst)528 IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) {
529 // Adjust offset to the way ARM CPUs read PC.
530 Offset -= kPCReadOffset;
531
532 assertCanEncodeBranchOffset(Offset);
533
534 // Properly preserve only the bits supported in the instruction.
535 Offset >>= 2;
536 Offset &= kBranchOffsetMask;
537 return (Inst & ~kBranchOffsetMask) | Offset;
538 }
539
encodeRegister(const Operand * OpReg,RegSetWanted WantedRegSet,const char * RegName,const char * InstName)540 IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet,
541 const char *RegName, const char *InstName) {
542 IValueT Reg = 0;
543 if (encodeOperand(OpReg, Reg, WantedRegSet) != EncodedAsRegister)
544 llvm::report_fatal_error(std::string(InstName) + ": Can't find register " +
545 RegName);
546 return Reg;
547 }
548
encodeGPRegister(const Operand * OpReg,const char * RegName,const char * InstName)549 IValueT encodeGPRegister(const Operand *OpReg, const char *RegName,
550 const char *InstName) {
551 return encodeRegister(OpReg, WantGPRegs, RegName, InstName);
552 }
553
encodeSRegister(const Operand * OpReg,const char * RegName,const char * InstName)554 IValueT encodeSRegister(const Operand *OpReg, const char *RegName,
555 const char *InstName) {
556 return encodeRegister(OpReg, WantSRegs, RegName, InstName);
557 }
558
encodeDRegister(const Operand * OpReg,const char * RegName,const char * InstName)559 IValueT encodeDRegister(const Operand *OpReg, const char *RegName,
560 const char *InstName) {
561 return encodeRegister(OpReg, WantDRegs, RegName, InstName);
562 }
563
encodeQRegister(const Operand * OpReg,const char * RegName,const char * InstName)564 IValueT encodeQRegister(const Operand *OpReg, const char *RegName,
565 const char *InstName) {
566 return encodeRegister(OpReg, WantQRegs, RegName, InstName);
567 }
568
verifyPOrNotW(IValueT Address,const char * InstName)569 void verifyPOrNotW(IValueT Address, const char *InstName) {
570 if (BuildDefs::minimal())
571 return;
572 if (!isBitSet(P, Address) && isBitSet(W, Address))
573 llvm::report_fatal_error(std::string(InstName) +
574 ": P=0 when W=1 not allowed");
575 }
576
verifyRegsNotEq(IValueT Reg1,const char * Reg1Name,IValueT Reg2,const char * Reg2Name,const char * InstName)577 void verifyRegsNotEq(IValueT Reg1, const char *Reg1Name, IValueT Reg2,
578 const char *Reg2Name, const char *InstName) {
579 if (BuildDefs::minimal())
580 return;
581 if (Reg1 == Reg2)
582 llvm::report_fatal_error(std::string(InstName) + ": " + Reg1Name + "=" +
583 Reg2Name + " not allowed");
584 }
585
verifyRegNotPc(IValueT Reg,const char * RegName,const char * InstName)586 void verifyRegNotPc(IValueT Reg, const char *RegName, const char *InstName) {
587 verifyRegsNotEq(Reg, RegName, RegARM32::Encoded_Reg_pc, "pc", InstName);
588 }
589
verifyAddrRegNotPc(IValueT RegShift,IValueT Address,const char * RegName,const char * InstName)590 void verifyAddrRegNotPc(IValueT RegShift, IValueT Address, const char *RegName,
591 const char *InstName) {
592 if (BuildDefs::minimal())
593 return;
594 if (getGPRReg(RegShift, Address) == RegARM32::Encoded_Reg_pc)
595 llvm::report_fatal_error(std::string(InstName) + ": " + RegName +
596 "=pc not allowed");
597 }
598
verifyRegNotPcWhenSetFlags(IValueT Reg,bool SetFlags,const char * InstName)599 void verifyRegNotPcWhenSetFlags(IValueT Reg, bool SetFlags,
600 const char *InstName) {
601 if (BuildDefs::minimal())
602 return;
603 if (SetFlags && (Reg == RegARM32::Encoded_Reg_pc))
604 llvm::report_fatal_error(std::string(InstName) + ": " +
605 RegARM32::getRegName(RegARM32::Reg_pc) +
606 "=pc not allowed when CC=1");
607 }
608
609 enum SIMDShiftType { ST_Vshl, ST_Vshr };
610
encodeSIMDShiftImm6(SIMDShiftType Shift,Type ElmtTy,const IValueT Imm)611 IValueT encodeSIMDShiftImm6(SIMDShiftType Shift, Type ElmtTy,
612 const IValueT Imm) {
613 assert(Imm > 0);
614 const SizeT MaxShift = getScalarIntBitWidth(ElmtTy);
615 assert(Imm < 2 * MaxShift);
616 assert(ElmtTy == IceType_i8 || ElmtTy == IceType_i16 ||
617 ElmtTy == IceType_i32);
618 const IValueT VshlImm = Imm - MaxShift;
619 const IValueT VshrImm = 2 * MaxShift - Imm;
620 return ((Shift == ST_Vshl) ? VshlImm : VshrImm) & (2 * MaxShift - 1);
621 }
622
encodeSIMDShiftImm6(SIMDShiftType Shift,Type ElmtTy,const ConstantInteger32 * Imm6)623 IValueT encodeSIMDShiftImm6(SIMDShiftType Shift, Type ElmtTy,
624 const ConstantInteger32 *Imm6) {
625 const IValueT Imm = Imm6->getValue();
626 return encodeSIMDShiftImm6(Shift, ElmtTy, Imm);
627 }
628 } // end of anonymous namespace
629
630 namespace Ice {
631 namespace ARM32 {
632
emit(GlobalContext * Ctx,const Assembler & Asm) const633 size_t MoveRelocatableFixup::emit(GlobalContext *Ctx,
634 const Assembler &Asm) const {
635 if (!BuildDefs::dump())
636 return InstARM32::InstSize;
637 Ostream &Str = Ctx->getStrEmit();
638 IValueT Inst = Asm.load<IValueT>(position());
639 const bool IsMovw = kind() == llvm::ELF::R_ARM_MOVW_ABS_NC ||
640 kind() == llvm::ELF::R_ARM_MOVW_PREL_NC;
641 const auto Symbol = symbol().toString();
642 const bool NeedsPCRelSuffix =
643 (Asm.fixupIsPCRel(kind()) || Symbol == GlobalOffsetTable);
644 Str << "\t"
645 "mov"
646 << (IsMovw ? "w" : "t") << "\t"
647 << RegARM32::getRegName(RegNumT::fixme((Inst >> kRdShift) & 0xF))
648 << ", #:" << (IsMovw ? "lower" : "upper") << "16:" << Symbol
649 << (NeedsPCRelSuffix ? " - ." : "")
650 << "\t@ .word "
651 // TODO(jpp): This is broken, it also needs to add a magic constant.
652 << llvm::format_hex_no_prefix(Inst, 8) << "\n";
653 return InstARM32::InstSize;
654 }
655
encodeElmtType(Type ElmtTy)656 IValueT AssemblerARM32::encodeElmtType(Type ElmtTy) {
657 switch (ElmtTy) {
658 case IceType_i8:
659 return 0;
660 case IceType_i16:
661 return 1;
662 case IceType_i32:
663 case IceType_f32:
664 return 2;
665 case IceType_i64:
666 return 3;
667 default:
668 llvm::report_fatal_error("SIMD op: Don't understand element type " +
669 typeStdString(ElmtTy));
670 }
671 }
672
673 // This fixup points to an ARM32 instruction with the following format:
emitOffset(Assembler * Asm) const674 void MoveRelocatableFixup::emitOffset(Assembler *Asm) const {
675 // cccc00110T00iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd,
676 // iiiiiiiiiiiiiiii = Imm16, and T=1 for movt.
677
678 const IValueT Inst = Asm->load<IValueT>(position());
679 constexpr IValueT Imm16Mask = 0x000F0FFF;
680 const IValueT Imm16 = offset() & 0xffff;
681 Asm->store(position(),
682 (Inst & ~Imm16Mask) | ((Imm16 >> 12) << 16) | (Imm16 & 0xfff));
683 }
684
createMoveFixup(bool IsMovW,const Constant * Value)685 MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW,
686 const Constant *Value) {
687 MoveRelocatableFixup *F =
688 new (allocate<MoveRelocatableFixup>()) MoveRelocatableFixup();
689 F->set_kind(IsMovW ? (IsNonsfi ? llvm::ELF::R_ARM_MOVW_PREL_NC
690 : llvm::ELF::R_ARM_MOVW_ABS_NC)
691 : (IsNonsfi ? llvm::ELF::R_ARM_MOVT_PREL
692 : llvm::ELF::R_ARM_MOVT_ABS));
693 F->set_value(Value);
694 Buffer.installFixup(F);
695 return F;
696 }
697
emit(GlobalContext * Ctx,const Assembler & Asm) const698 size_t BlRelocatableFixup::emit(GlobalContext *Ctx,
699 const Assembler &Asm) const {
700 if (!BuildDefs::dump())
701 return InstARM32::InstSize;
702 Ostream &Str = Ctx->getStrEmit();
703 IValueT Inst = Asm.load<IValueT>(position());
704 Str << "\t"
705 "bl\t"
706 << symbol() << "\t@ .word " << llvm::format_hex_no_prefix(Inst, 8)
707 << "\n";
708 return InstARM32::InstSize;
709 }
710
emitOffset(Assembler * Asm) const711 void BlRelocatableFixup::emitOffset(Assembler *Asm) const {
712 // cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and
713 // iiiiiiiiiiiiiiiiiiiiiiii=
714 // EncodedBranchOffset(cccc101l000000000000000000000000, Offset);
715 const IValueT Inst = Asm->load<IValueT>(position());
716 constexpr IValueT OffsetMask = 0x00FFFFFF;
717 Asm->store(position(), encodeBranchOffset(offset(), Inst & ~OffsetMask));
718 }
719
padWithNop(intptr_t Padding)720 void AssemblerARM32::padWithNop(intptr_t Padding) {
721 constexpr intptr_t InstWidth = sizeof(IValueT);
722 assert(Padding % InstWidth == 0 &&
723 "Padding not multiple of instruction size");
724 for (intptr_t i = 0; i < Padding; i += InstWidth)
725 nop();
726 }
727
728 BlRelocatableFixup *
createBlFixup(const ConstantRelocatable * BlTarget)729 AssemblerARM32::createBlFixup(const ConstantRelocatable *BlTarget) {
730 BlRelocatableFixup *F =
731 new (allocate<BlRelocatableFixup>()) BlRelocatableFixup();
732 F->set_kind(llvm::ELF::R_ARM_CALL);
733 F->set_value(BlTarget);
734 Buffer.installFixup(F);
735 return F;
736 }
737
bindCfgNodeLabel(const CfgNode * Node)738 void AssemblerARM32::bindCfgNodeLabel(const CfgNode *Node) {
739 if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) {
740 // Generate label name so that branches can find it.
741 constexpr SizeT InstSize = 0;
742 emitTextInst(Node->getAsmName() + ":", InstSize);
743 }
744 SizeT NodeNumber = Node->getIndex();
745 assert(!getPreliminary());
746 Label *L = getOrCreateCfgNodeLabel(NodeNumber);
747 this->bind(L);
748 }
749
getOrCreateLabel(SizeT Number,LabelVector & Labels)750 Label *AssemblerARM32::getOrCreateLabel(SizeT Number, LabelVector &Labels) {
751 Label *L = nullptr;
752 if (Number == Labels.size()) {
753 L = new (this->allocate<Label>()) Label();
754 Labels.push_back(L);
755 return L;
756 }
757 if (Number > Labels.size()) {
758 Labels.resize(Number + 1);
759 }
760 L = Labels[Number];
761 if (!L) {
762 L = new (this->allocate<Label>()) Label();
763 Labels[Number] = L;
764 }
765 return L;
766 }
767
768 // Pull out offset from branch Inst.
decodeBranchOffset(IValueT Inst)769 IOffsetT AssemblerARM32::decodeBranchOffset(IValueT Inst) {
770 // Sign-extend, left-shift by 2, and adjust to the way ARM CPUs read PC.
771 const IOffsetT Offset = (Inst & kBranchOffsetMask) << 8;
772 return (Offset >> 6) + kPCReadOffset;
773 }
774
bind(Label * L)775 void AssemblerARM32::bind(Label *L) {
776 IOffsetT BoundPc = Buffer.size();
777 assert(!L->isBound()); // Labels can only be bound once.
778 while (L->isLinked()) {
779 IOffsetT Position = L->getLinkPosition();
780 IOffsetT Dest = BoundPc - Position;
781 IValueT Inst = Buffer.load<IValueT>(Position);
782 Buffer.store<IValueT>(Position, encodeBranchOffset(Dest, Inst));
783 L->setPosition(decodeBranchOffset(Inst));
784 }
785 L->bindTo(BoundPc);
786 }
787
emitTextInst(const std::string & Text,SizeT InstSize)788 void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) {
789 AssemblerFixup *F = createTextFixup(Text, InstSize);
790 emitFixup(F);
791 for (SizeT I = 0; I < InstSize; ++I) {
792 AssemblerBuffer::EnsureCapacity ensured(&Buffer);
793 Buffer.emit<char>(0);
794 }
795 }
796
emitType01(CondARM32::Cond Cond,IValueT InstType,IValueT Opcode,bool SetFlags,IValueT Rn,IValueT Rd,IValueT Imm12,EmitChecks RuleChecks,const char * InstName)797 void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT InstType,
798 IValueT Opcode, bool SetFlags, IValueT Rn,
799 IValueT Rd, IValueT Imm12,
800 EmitChecks RuleChecks, const char *InstName) {
801 switch (RuleChecks) {
802 case NoChecks:
803 break;
804 case RdIsPcAndSetFlags:
805 verifyRegNotPcWhenSetFlags(Rd, SetFlags, InstName);
806 break;
807 }
808 assert(Rd < RegARM32::getNumGPRegs());
809 assert(CondARM32::isDefined(Cond));
810 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
811 (InstType << kTypeShift) | (Opcode << kOpcodeShift) |
812 (encodeBool(SetFlags) << kSShift) |
813 (Rn << kRnShift) | (Rd << kRdShift) | Imm12;
814 emitInst(Encoding);
815 }
816
emitType01(CondARM32::Cond Cond,IValueT Opcode,const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,EmitChecks RuleChecks,const char * InstName)817 void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode,
818 const Operand *OpRd, const Operand *OpRn,
819 const Operand *OpSrc1, bool SetFlags,
820 EmitChecks RuleChecks, const char *InstName) {
821 IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
822 IValueT Rn = encodeGPRegister(OpRn, "Rn", InstName);
823 emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, RuleChecks, InstName);
824 }
825
emitType01(CondARM32::Cond Cond,IValueT Opcode,IValueT Rd,IValueT Rn,const Operand * OpSrc1,bool SetFlags,EmitChecks RuleChecks,const char * InstName)826 void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode,
827 IValueT Rd, IValueT Rn, const Operand *OpSrc1,
828 bool SetFlags, EmitChecks RuleChecks,
829 const char *InstName) {
830 IValueT Src1Value;
831 // TODO(kschimpf) Other possible decodings of data operations.
832 switch (encodeOperand(OpSrc1, Src1Value, WantGPRegs)) {
833 default:
834 llvm::report_fatal_error(std::string(InstName) +
835 ": Can't encode instruction");
836 return;
837 case EncodedAsRegister: {
838 // XXX (register)
839 // xxx{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>}
840 //
841 // cccc000xxxxsnnnnddddiiiiitt0mmmm where cccc=Cond, xxxx=Opcode, dddd=Rd,
842 // nnnn=Rn, mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
843 constexpr IValueT Imm5 = 0;
844 Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, Imm5);
845 emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value,
846 RuleChecks, InstName);
847 return;
848 }
849 case EncodedAsShiftedRegister: {
850 // Form is defined in case EncodedAsRegister. (i.e. XXX (register)).
851 emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value,
852 RuleChecks, InstName);
853 return;
854 }
855 case EncodedAsConstI32: {
856 // See if we can convert this to an XXX (immediate).
857 IValueT RotateAmt;
858 IValueT Imm8;
859 if (!OperandARM32FlexImm::canHoldImm(Src1Value, &RotateAmt, &Imm8))
860 llvm::report_fatal_error(std::string(InstName) +
861 ": Immediate rotated constant not valid");
862 Src1Value = encodeRotatedImm8(RotateAmt, Imm8);
863 // Intentionally fall to next case!
864 }
865 case EncodedAsRotatedImm8: {
866 // XXX (Immediate)
867 // xxx{s}<c> <Rd>, <Rn>, #<RotatedImm8>
868 //
869 // cccc001xxxxsnnnnddddiiiiiiiiiiii where cccc=Cond, xxxx=Opcode, dddd=Rd,
870 // nnnn=Rn, s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
871 emitType01(Cond, kInstTypeDataImmediate, Opcode, SetFlags, Rn, Rd,
872 Src1Value, RuleChecks, InstName);
873 return;
874 }
875 case EncodedAsRegShiftReg: {
876 // XXX (register-shifted reg)
877 // xxx{s}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>
878 //
879 // cccc000xxxxfnnnnddddssss0tt1mmmm where cccc=Cond, xxxx=Opcode, dddd=Rd,
880 // nnnn=Rn, ssss=Rs, f=SetFlags, tt is encoding of type, and
881 // Src1Value=ssss01tt1mmmm.
882 emitType01(Cond, kInstTypeDataRegShift, Opcode, SetFlags, Rn, Rd, Src1Value,
883 RuleChecks, InstName);
884 return;
885 }
886 }
887 }
888
emitType05(CondARM32::Cond Cond,IOffsetT Offset,bool Link)889 void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset,
890 bool Link) {
891 // cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and
892 // iiiiiiiiiiiiiiiiiiiiiiii=
893 // EncodedBranchOffset(cccc101l000000000000000000000000, Offset);
894 assert(CondARM32::isDefined(Cond));
895 IValueT Encoding = static_cast<int32_t>(Cond) << kConditionShift |
896 5 << kTypeShift | (Link ? 1 : 0) << kLinkShift;
897 Encoding = encodeBranchOffset(Offset, Encoding);
898 emitInst(Encoding);
899 }
900
emitBranch(Label * L,CondARM32::Cond Cond,bool Link)901 void AssemblerARM32::emitBranch(Label *L, CondARM32::Cond Cond, bool Link) {
902 // TODO(kschimpf): Handle far jumps.
903 if (L->isBound()) {
904 const int32_t Dest = L->getPosition() - Buffer.size();
905 emitType05(Cond, Dest, Link);
906 return;
907 }
908 const IOffsetT Position = Buffer.size();
909 // Use the offset field of the branch instruction for linking the sites.
910 emitType05(Cond, L->getEncodedPosition(), Link);
911 L->linkTo(*this, Position);
912 }
913
emitCompareOp(CondARM32::Cond Cond,IValueT Opcode,const Operand * OpRn,const Operand * OpSrc1,const char * InstName)914 void AssemblerARM32::emitCompareOp(CondARM32::Cond Cond, IValueT Opcode,
915 const Operand *OpRn, const Operand *OpSrc1,
916 const char *InstName) {
917 // XXX (register)
918 // XXX<c> <Rn>, <Rm>{, <shift>}
919 //
920 // ccccyyyxxxx1nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm, iiiii
921 // defines shift constant, tt=ShiftKind, yyy=kInstTypeDataRegister, and
922 // xxxx=Opcode.
923 //
924 // XXX (immediate)
925 // XXX<c> <Rn>, #<RotatedImm8>
926 //
927 // ccccyyyxxxx1nnnn0000iiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
928 // yyy=kInstTypeDataImmdiate, xxxx=Opcode, and iiiiiiiiiiii=Src1Value
929 // defining RotatedImm8.
930 constexpr bool SetFlags = true;
931 constexpr IValueT Rd = RegARM32::Encoded_Reg_r0;
932 IValueT Rn = encodeGPRegister(OpRn, "Rn", InstName);
933 emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, NoChecks, InstName);
934 }
935
emitMemOp(CondARM32::Cond Cond,IValueT InstType,bool IsLoad,bool IsByte,IValueT Rt,IValueT Address)936 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType,
937 bool IsLoad, bool IsByte, IValueT Rt,
938 IValueT Address) {
939 assert(Rt < RegARM32::getNumGPRegs());
940 assert(CondARM32::isDefined(Cond));
941 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
942 (InstType << kTypeShift) | (IsLoad ? L : 0) |
943 (IsByte ? B : 0) | (Rt << kRdShift) | Address;
944 emitInst(Encoding);
945 }
946
emitMemOp(CondARM32::Cond Cond,bool IsLoad,bool IsByte,IValueT Rt,const Operand * OpAddress,const TargetInfo & TInfo,const char * InstName)947 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte,
948 IValueT Rt, const Operand *OpAddress,
949 const TargetInfo &TInfo, const char *InstName) {
950 IValueT Address;
951 switch (encodeAddress(OpAddress, Address, TInfo, Imm12Address)) {
952 default:
953 llvm::report_fatal_error(std::string(InstName) +
954 ": Memory address not understood");
955 case EncodedAsImmRegOffset: {
956 // XXX{B} (immediate):
957 // xxx{b}<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
958 // xxx{b}<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
959 // xxx{b}<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
960 //
961 // cccc010pubwlnnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
962 // iiiiiiiiiiii=imm12, b=IsByte, pu0w<<21 is a BlockAddr, l=IsLoad, and
963 // pu0w0nnnn0000iiiiiiiiiiii=Address.
964 RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
965
966 // Check if conditions of rules violated.
967 verifyRegNotPc(Rn, "Rn", InstName);
968 verifyPOrNotW(Address, InstName);
969 if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) &&
970 isBitSet(U, Address) && !isBitSet(W, Address) &&
971 (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
972 llvm::report_fatal_error(std::string(InstName) +
973 ": Use push/pop instead");
974
975 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
976 return;
977 }
978 case EncodedAsShiftRotateImm5: {
979 // XXX{B} (register)
980 // xxx{b}<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
981 // xxx{b}<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
982 //
983 // cccc011pubwlnnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt,
984 // b=IsByte, U=1 if +, pu0b is a BlockAddr, l=IsLoad, and
985 // pu0w0nnnn0000iiiiiss0mmmm=Address.
986 RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
987 RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address);
988
989 // Check if conditions of rules violated.
990 verifyPOrNotW(Address, InstName);
991 verifyRegNotPc(Rm, "Rm", InstName);
992 if (IsByte)
993 verifyRegNotPc(Rt, "Rt", InstName);
994 if (isBitSet(W, Address)) {
995 verifyRegNotPc(Rn, "Rn", InstName);
996 verifyRegsNotEq(Rn, "Rn", Rt, "Rt", InstName);
997 }
998 emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address);
999 return;
1000 }
1001 }
1002 }
1003
emitMemOpEnc3(CondARM32::Cond Cond,IValueT Opcode,IValueT Rt,const Operand * OpAddress,const TargetInfo & TInfo,const char * InstName)1004 void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode,
1005 IValueT Rt, const Operand *OpAddress,
1006 const TargetInfo &TInfo,
1007 const char *InstName) {
1008 IValueT Address;
1009 switch (encodeAddress(OpAddress, Address, TInfo, RotatedImm8Enc3Address)) {
1010 default:
1011 llvm::report_fatal_error(std::string(InstName) +
1012 ": Memory address not understood");
1013 case EncodedAsImmRegOffset: {
1014 // XXXH (immediate)
1015 // xxxh<c> <Rt>, [<Rn>{, #+-<Imm8>}]
1016 // xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>]
1017 // xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>]!
1018 //
1019 // cccc000pu0wxnnnnttttiiiiyyyyjjjj where cccc=Cond, nnnn=Rn, tttt=Rt,
1020 // iiiijjjj=Imm8, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode,
1021 // and pu0w0nnnn0000iiii0000jjjj=Address.
1022 assert(Rt < RegARM32::getNumGPRegs());
1023 assert(CondARM32::isDefined(Cond));
1024 verifyPOrNotW(Address, InstName);
1025 verifyRegNotPc(Rt, "Rt", InstName);
1026 if (isBitSet(W, Address))
1027 verifyRegsNotEq(getGPRReg(kRnShift, Address), "Rn", Rt, "Rt", InstName);
1028 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
1029 Opcode | (Rt << kRdShift) | Address;
1030 emitInst(Encoding);
1031 return;
1032 }
1033 case EncodedAsShiftRotateImm5: {
1034 // XXXH (register)
1035 // xxxh<c> <Rt>, [<Rn>, +/-<Rm>]{!}
1036 // xxxh<c> <Rt>, [<Rn>], +/-<Rm>
1037 //
1038 // cccc000pu0wxnnnntttt00001011mmmm where cccc=Cond, tttt=Rt, nnnn=Rn,
1039 // mmmm=Rm, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, and
1040 // pu0w0nnnn000000000000mmmm=Address.
1041 assert(Rt < RegARM32::getNumGPRegs());
1042 assert(CondARM32::isDefined(Cond));
1043 verifyPOrNotW(Address, InstName);
1044 verifyRegNotPc(Rt, "Rt", InstName);
1045 verifyAddrRegNotPc(kRmShift, Address, "Rm", InstName);
1046 const RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
1047 if (isBitSet(W, Address)) {
1048 verifyRegNotPc(Rn, "Rn", InstName);
1049 verifyRegsNotEq(Rn, "Rn", Rt, "Rt", InstName);
1050 }
1051 if (mask(Address, kShiftImmShift, 5) != 0)
1052 // For encoding 3, no shift is allowed.
1053 llvm::report_fatal_error(std::string(InstName) +
1054 ": Shift constant not allowed");
1055 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
1056 Opcode | (Rt << kRdShift) | Address;
1057 emitInst(Encoding);
1058 return;
1059 }
1060 }
1061 }
1062
emitDivOp(CondARM32::Cond Cond,IValueT Opcode,IValueT Rd,IValueT Rn,IValueT Rm)1063 void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
1064 IValueT Rn, IValueT Rm) {
1065 assert(Rd < RegARM32::getNumGPRegs());
1066 assert(Rn < RegARM32::getNumGPRegs());
1067 assert(Rm < RegARM32::getNumGPRegs());
1068 assert(CondARM32::isDefined(Cond));
1069 const IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
1070 (Rn << kDivRnShift) | (Rd << kDivRdShift) | B26 |
1071 B25 | B24 | B20 | B15 | B14 | B13 | B12 | B4 |
1072 (Rm << kDivRmShift);
1073 emitInst(Encoding);
1074 }
1075
emitInsertExtractInt(CondARM32::Cond Cond,const Operand * OpQn,uint32_t Index,const Operand * OpRt,bool IsExtract,const char * InstName)1076 void AssemblerARM32::emitInsertExtractInt(CondARM32::Cond Cond,
1077 const Operand *OpQn, uint32_t Index,
1078 const Operand *OpRt, bool IsExtract,
1079 const char *InstName) {
1080 const IValueT Rt = encodeGPRegister(OpRt, "Rt", InstName);
1081 IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", InstName));
1082 assert(Rt != RegARM32::Encoded_Reg_pc);
1083 assert(Rt != RegARM32::Encoded_Reg_sp);
1084 assert(CondARM32::isDefined(Cond));
1085 const uint32_t BitSize = typeWidthInBytes(OpRt->getType()) * CHAR_BIT;
1086 IValueT Opcode1 = 0;
1087 IValueT Opcode2 = 0;
1088 switch (BitSize) {
1089 default:
1090 llvm::report_fatal_error(std::string(InstName) +
1091 ": Unable to process type " +
1092 typeStdString(OpRt->getType()));
1093 case 8:
1094 assert(Index < 16);
1095 Dn = Dn | mask(Index, 3, 1);
1096 Opcode1 = B1 | mask(Index, 2, 1);
1097 Opcode2 = mask(Index, 0, 2);
1098 break;
1099 case 16:
1100 assert(Index < 8);
1101 Dn = Dn | mask(Index, 2, 1);
1102 Opcode1 = mask(Index, 1, 1);
1103 Opcode2 = (mask(Index, 0, 1) << 1) | B0;
1104 break;
1105 case 32:
1106 assert(Index < 4);
1107 Dn = Dn | mask(Index, 1, 1);
1108 Opcode1 = mask(Index, 0, 1);
1109 break;
1110 }
1111 const IValueT Encoding = B27 | B26 | B25 | B11 | B9 | B8 | B4 |
1112 (encodeCondition(Cond) << kConditionShift) |
1113 (Opcode1 << 21) |
1114 (getXXXXInRegYXXXX(Dn) << kRnShift) | (Rt << 12) |
1115 (encodeBool(IsExtract) << 20) |
1116 (getYInRegYXXXX(Dn) << 7) | (Opcode2 << 5);
1117 emitInst(Encoding);
1118 }
1119
emitMoveSS(CondARM32::Cond Cond,IValueT Sd,IValueT Sm)1120 void AssemblerARM32::emitMoveSS(CondARM32::Cond Cond, IValueT Sd, IValueT Sm) {
1121 // VMOV (register) - ARM section A8.8.340, encoding A2:
1122 // vmov<c>.f32 <Sd>, <Sm>
1123 //
1124 // cccc11101D110000dddd101001M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
1125 constexpr IValueT VmovssOpcode = B23 | B21 | B20 | B6;
1126 constexpr IValueT S0 = 0;
1127 emitVFPsss(Cond, VmovssOpcode, Sd, S0, Sm);
1128 }
1129
emitMulOp(CondARM32::Cond Cond,IValueT Opcode,IValueT Rd,IValueT Rn,IValueT Rm,IValueT Rs,bool SetFlags)1130 void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
1131 IValueT Rn, IValueT Rm, IValueT Rs,
1132 bool SetFlags) {
1133 assert(Rd < RegARM32::getNumGPRegs());
1134 assert(Rn < RegARM32::getNumGPRegs());
1135 assert(Rm < RegARM32::getNumGPRegs());
1136 assert(Rs < RegARM32::getNumGPRegs());
1137 assert(CondARM32::isDefined(Cond));
1138 IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
1139 (encodeBool(SetFlags) << kSShift) | (Rn << kRnShift) |
1140 (Rd << kRdShift) | (Rs << kRsShift) | B7 | B4 |
1141 (Rm << kRmShift);
1142 emitInst(Encoding);
1143 }
1144
emitMultiMemOp(CondARM32::Cond Cond,BlockAddressMode AddressMode,bool IsLoad,IValueT BaseReg,IValueT Registers)1145 void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond,
1146 BlockAddressMode AddressMode, bool IsLoad,
1147 IValueT BaseReg, IValueT Registers) {
1148 assert(CondARM32::isDefined(Cond));
1149 assert(BaseReg < RegARM32::getNumGPRegs());
1150 assert(Registers < (1 << RegARM32::getNumGPRegs()));
1151 IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 |
1152 AddressMode | (IsLoad ? L : 0) | (BaseReg << kRnShift) |
1153 Registers;
1154 emitInst(Encoding);
1155 }
1156
emitSignExtend(CondARM32::Cond Cond,IValueT Opcode,const Operand * OpRd,const Operand * OpSrc0,const char * InstName)1157 void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode,
1158 const Operand *OpRd, const Operand *OpSrc0,
1159 const char *InstName) {
1160 IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
1161 IValueT Rm = encodeGPRegister(OpSrc0, "Rm", InstName);
1162 // Note: For the moment, we assume no rotation is specified.
1163 RotationValue Rotation = kRotateNone;
1164 constexpr IValueT Rn = RegARM32::Encoded_Reg_pc;
1165 const Type Ty = OpSrc0->getType();
1166 switch (Ty) {
1167 default:
1168 llvm::report_fatal_error(std::string(InstName) + ": Type " +
1169 typeString(Ty) + " not allowed");
1170 break;
1171 case IceType_i1:
1172 case IceType_i8: {
1173 // SXTB/UXTB - Arm sections A8.8.233 and A8.8.274, encoding A1:
1174 // sxtb<c> <Rd>, <Rm>{, <rotate>}
1175 // uxtb<c> <Rd>, <Rm>{, <rotate>}
1176 //
1177 // ccccxxxxxxxx1111ddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
1178 // dddd=Rd, mmmm=Rm, and rr defined (RotationValue) rotate.
1179 break;
1180 }
1181 case IceType_i16: {
1182 // SXTH/UXTH - ARM sections A8.8.235 and A8.8.276, encoding A1:
1183 // uxth<c> <Rd>< <Rm>{, <rotate>}
1184 //
1185 // cccc01101111nnnnddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and
1186 // rr defined (RotationValue) rotate.
1187 Opcode |= B20;
1188 break;
1189 }
1190 }
1191
1192 assert(CondARM32::isDefined(Cond));
1193 IValueT Rot = encodeRotation(Rotation);
1194 if (!Utils::IsUint(2, Rot))
1195 llvm::report_fatal_error(std::string(InstName) +
1196 ": Illegal rotation value");
1197 IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | Opcode |
1198 (Rn << kRnShift) | (Rd << kRdShift) |
1199 (Rot << kRotationShift) | B6 | B5 | B4 | (Rm << kRmShift);
1200 emitInst(Encoding);
1201 }
1202
emitSIMDBase(IValueT Opcode,IValueT Dd,IValueT Dn,IValueT Dm,bool UseQRegs,bool IsFloatTy)1203 void AssemblerARM32::emitSIMDBase(IValueT Opcode, IValueT Dd, IValueT Dn,
1204 IValueT Dm, bool UseQRegs, bool IsFloatTy) {
1205 const IValueT Encoding =
1206 Opcode | B25 | (encodeCondition(CondARM32::kNone) << kConditionShift) |
1207 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) |
1208 (getXXXXInRegYXXXX(Dd) << 12) | (IsFloatTy ? B10 : 0) |
1209 (getYInRegYXXXX(Dn) << 7) | (encodeBool(UseQRegs) << 6) |
1210 (getYInRegYXXXX(Dm) << 5) | getXXXXInRegYXXXX(Dm);
1211 emitInst(Encoding);
1212 }
1213
emitSIMD(IValueT Opcode,Type ElmtTy,IValueT Dd,IValueT Dn,IValueT Dm,bool UseQRegs)1214 void AssemblerARM32::emitSIMD(IValueT Opcode, Type ElmtTy, IValueT Dd,
1215 IValueT Dn, IValueT Dm, bool UseQRegs) {
1216 constexpr IValueT ElmtShift = 20;
1217 const IValueT ElmtSize = encodeElmtType(ElmtTy);
1218 assert(Utils::IsUint(2, ElmtSize));
1219 emitSIMDBase(Opcode | (ElmtSize << ElmtShift), Dd, Dn, Dm, UseQRegs,
1220 isFloatingType(ElmtTy));
1221 }
1222
emitSIMDqqqBase(IValueT Opcode,const Operand * OpQd,const Operand * OpQn,const Operand * OpQm,bool IsFloatTy,const char * OpcodeName)1223 void AssemblerARM32::emitSIMDqqqBase(IValueT Opcode, const Operand *OpQd,
1224 const Operand *OpQn, const Operand *OpQm,
1225 bool IsFloatTy, const char *OpcodeName) {
1226 const IValueT Qd = encodeQRegister(OpQd, "Qd", OpcodeName);
1227 const IValueT Qn = encodeQRegister(OpQn, "Qn", OpcodeName);
1228 const IValueT Qm = encodeQRegister(OpQm, "Qm", OpcodeName);
1229 constexpr bool UseQRegs = true;
1230 emitSIMDBase(Opcode, mapQRegToDReg(Qd), mapQRegToDReg(Qn), mapQRegToDReg(Qm),
1231 UseQRegs, IsFloatTy);
1232 }
1233
emitSIMDqqq(IValueT Opcode,Type ElmtTy,const Operand * OpQd,const Operand * OpQn,const Operand * OpQm,const char * OpcodeName)1234 void AssemblerARM32::emitSIMDqqq(IValueT Opcode, Type ElmtTy,
1235 const Operand *OpQd, const Operand *OpQn,
1236 const Operand *OpQm, const char *OpcodeName) {
1237 constexpr IValueT ElmtShift = 20;
1238 const IValueT ElmtSize = encodeElmtType(ElmtTy);
1239 assert(Utils::IsUint(2, ElmtSize));
1240 emitSIMDqqqBase(Opcode | (ElmtSize << ElmtShift), OpQd, OpQn, OpQm,
1241 isFloatingType(ElmtTy), OpcodeName);
1242 }
1243
emitSIMDShiftqqc(IValueT Opcode,const Operand * OpQd,const Operand * OpQm,const IValueT Imm6,const char * OpcodeName)1244 void AssemblerARM32::emitSIMDShiftqqc(IValueT Opcode, const Operand *OpQd,
1245 const Operand *OpQm, const IValueT Imm6,
1246 const char *OpcodeName) {
1247 const IValueT Qd = encodeQRegister(OpQd, "Qd", OpcodeName);
1248 const IValueT Qn = 0;
1249 const IValueT Qm = encodeQRegister(OpQm, "Qm", OpcodeName);
1250 constexpr bool UseQRegs = true;
1251 constexpr bool IsFloatTy = false;
1252 constexpr IValueT ElmtShift = 16;
1253 emitSIMDBase(Opcode | (Imm6 << ElmtShift), mapQRegToDReg(Qd),
1254 mapQRegToDReg(Qn), mapQRegToDReg(Qm), UseQRegs, IsFloatTy);
1255 }
1256
emitSIMDCvtqq(IValueT Opcode,const Operand * OpQd,const Operand * OpQm,const char * OpcodeName)1257 void AssemblerARM32::emitSIMDCvtqq(IValueT Opcode, const Operand *OpQd,
1258 const Operand *OpQm,
1259 const char *OpcodeName) {
1260 const IValueT SIMDOpcode =
1261 B24 | B23 | B21 | B20 | B19 | B17 | B16 | B10 | B9 | Opcode;
1262 constexpr bool UseQRegs = true;
1263 constexpr bool IsFloatTy = false;
1264 const IValueT Qd = encodeQRegister(OpQd, "Qd", OpcodeName);
1265 constexpr IValueT Qn = 0;
1266 const IValueT Qm = encodeQRegister(OpQm, "Qm", OpcodeName);
1267 emitSIMDBase(SIMDOpcode, mapQRegToDReg(Qd), mapQRegToDReg(Qn),
1268 mapQRegToDReg(Qm), UseQRegs, IsFloatTy);
1269 }
1270
emitVFPddd(CondARM32::Cond Cond,IValueT Opcode,IValueT Dd,IValueT Dn,IValueT Dm)1271 void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode,
1272 IValueT Dd, IValueT Dn, IValueT Dm) {
1273 assert(Dd < RegARM32::getNumDRegs());
1274 assert(Dn < RegARM32::getNumDRegs());
1275 assert(Dm < RegARM32::getNumDRegs());
1276 assert(CondARM32::isDefined(Cond));
1277 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9 | B8;
1278 const IValueT Encoding =
1279 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
1280 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) |
1281 (getXXXXInRegYXXXX(Dd) << 12) | (getYInRegYXXXX(Dn) << 7) |
1282 (getYInRegYXXXX(Dm) << 5) | getXXXXInRegYXXXX(Dm);
1283 emitInst(Encoding);
1284 }
1285
emitVFPddd(CondARM32::Cond Cond,IValueT Opcode,const Operand * OpDd,const Operand * OpDn,const Operand * OpDm,const char * InstName)1286 void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode,
1287 const Operand *OpDd, const Operand *OpDn,
1288 const Operand *OpDm, const char *InstName) {
1289 IValueT Dd = encodeDRegister(OpDd, "Dd", InstName);
1290 IValueT Dn = encodeDRegister(OpDn, "Dn", InstName);
1291 IValueT Dm = encodeDRegister(OpDm, "Dm", InstName);
1292 emitVFPddd(Cond, Opcode, Dd, Dn, Dm);
1293 }
1294
emitVFPsss(CondARM32::Cond Cond,IValueT Opcode,IValueT Sd,IValueT Sn,IValueT Sm)1295 void AssemblerARM32::emitVFPsss(CondARM32::Cond Cond, IValueT Opcode,
1296 IValueT Sd, IValueT Sn, IValueT Sm) {
1297 assert(Sd < RegARM32::getNumSRegs());
1298 assert(Sn < RegARM32::getNumSRegs());
1299 assert(Sm < RegARM32::getNumSRegs());
1300 assert(CondARM32::isDefined(Cond));
1301 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9;
1302 const IValueT Encoding =
1303 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
1304 (getYInRegXXXXY(Sd) << 22) | (getXXXXInRegXXXXY(Sn) << 16) |
1305 (getXXXXInRegXXXXY(Sd) << 12) | (getYInRegXXXXY(Sn) << 7) |
1306 (getYInRegXXXXY(Sm) << 5) | getXXXXInRegXXXXY(Sm);
1307 emitInst(Encoding);
1308 }
1309
emitVFPsss(CondARM32::Cond Cond,IValueT Opcode,const Operand * OpSd,const Operand * OpSn,const Operand * OpSm,const char * InstName)1310 void AssemblerARM32::emitVFPsss(CondARM32::Cond Cond, IValueT Opcode,
1311 const Operand *OpSd, const Operand *OpSn,
1312 const Operand *OpSm, const char *InstName) {
1313 const IValueT Sd = encodeSRegister(OpSd, "Sd", InstName);
1314 const IValueT Sn = encodeSRegister(OpSn, "Sn", InstName);
1315 const IValueT Sm = encodeSRegister(OpSm, "Sm", InstName);
1316 emitVFPsss(Cond, Opcode, Sd, Sn, Sm);
1317 }
1318
adc(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1319 void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn,
1320 const Operand *OpSrc1, bool SetFlags,
1321 CondARM32::Cond Cond) {
1322 // ADC (register) - ARM section 18.8.2, encoding A1:
1323 // adc{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
1324 //
1325 // cccc0000101snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
1326 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
1327 //
1328 // ADC (Immediate) - ARM section A8.8.1, encoding A1:
1329 // adc{s}<c> <Rd>, <Rn>, #<RotatedImm8>
1330 //
1331 // cccc0010101snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
1332 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1333 constexpr const char *AdcName = "adc";
1334 constexpr IValueT AdcOpcode = B2 | B0; // 0101
1335 emitType01(Cond, AdcOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
1336 AdcName);
1337 }
1338
add(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1339 void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
1340 const Operand *OpSrc1, bool SetFlags,
1341 CondARM32::Cond Cond) {
1342 // ADD (register) - ARM section A8.8.7, encoding A1:
1343 // add{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>}
1344 // ADD (Sp plus register) - ARM section A8.8.11, encoding A1:
1345 // add{s}<c> sp, <Rn>, <Rm>{, <shiff>}
1346 //
1347 // cccc0000100snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
1348 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
1349 //
1350 // ADD (Immediate) - ARM section A8.8.5, encoding A1:
1351 // add{s}<c> <Rd>, <Rn>, #<RotatedImm8>
1352 // ADD (SP plus immediate) - ARM section A8.8.9, encoding A1.
1353 // add{s}<c> <Rd>, sp, #<RotatedImm8>
1354 //
1355 // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
1356 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1357 constexpr const char *AddName = "add";
1358 constexpr IValueT Add = B2; // 0100
1359 emitType01(Cond, Add, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
1360 AddName);
1361 }
1362
and_(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1363 void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn,
1364 const Operand *OpSrc1, bool SetFlags,
1365 CondARM32::Cond Cond) {
1366 // AND (register) - ARM section A8.8.14, encoding A1:
1367 // and{s}<c> <Rd>, <Rn>{, <shift>}
1368 //
1369 // cccc0000000snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
1370 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
1371 //
1372 // AND (Immediate) - ARM section A8.8.13, encoding A1:
1373 // and{s}<c> <Rd>, <Rn>, #<RotatedImm8>
1374 //
1375 // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
1376 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1377 constexpr const char *AndName = "and";
1378 constexpr IValueT And = 0; // 0000
1379 emitType01(Cond, And, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
1380 AndName);
1381 }
1382
b(Label * L,CondARM32::Cond Cond)1383 void AssemblerARM32::b(Label *L, CondARM32::Cond Cond) {
1384 emitBranch(L, Cond, false);
1385 }
1386
bkpt(uint16_t Imm16)1387 void AssemblerARM32::bkpt(uint16_t Imm16) {
1388 // BKPT - ARM section A*.8.24 - encoding A1:
1389 // bkpt #<Imm16>
1390 //
1391 // cccc00010010iiiiiiiiiiii0111iiii where cccc=AL and iiiiiiiiiiiiiiii=Imm16
1392 const IValueT Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 |
1393 ((Imm16 >> 4) << 8) | B6 | B5 | B4 | (Imm16 & 0xf);
1394 emitInst(Encoding);
1395 }
1396
bic(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1397 void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn,
1398 const Operand *OpSrc1, bool SetFlags,
1399 CondARM32::Cond Cond) {
1400 // BIC (register) - ARM section A8.8.22, encoding A1:
1401 // bic{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
1402 //
1403 // cccc0001110snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
1404 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
1405 //
1406 // BIC (immediate) - ARM section A8.8.21, encoding A1:
1407 // bic{s}<c> <Rd>, <Rn>, #<RotatedImm8>
1408 //
1409 // cccc0011110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rn, nnnn=Rn,
1410 // s=SetFlags, and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1411 constexpr const char *BicName = "bic";
1412 constexpr IValueT BicOpcode = B3 | B2 | B1; // i.e. 1110
1413 emitType01(Cond, BicOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
1414 BicName);
1415 }
1416
bl(const ConstantRelocatable * Target)1417 void AssemblerARM32::bl(const ConstantRelocatable *Target) {
1418 // BL (immediate) - ARM section A8.8.25, encoding A1:
1419 // bl<c> <label>
1420 //
1421 // cccc1011iiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond (not currently allowed)
1422 // and iiiiiiiiiiiiiiiiiiiiiiii is the (encoded) Target to branch to.
1423 emitFixup(createBlFixup(Target));
1424 constexpr CondARM32::Cond Cond = CondARM32::AL;
1425 constexpr IValueT Immed = 0;
1426 constexpr bool Link = true;
1427 emitType05(Cond, Immed, Link);
1428 }
1429
blx(const Operand * Target)1430 void AssemblerARM32::blx(const Operand *Target) {
1431 // BLX (register) - ARM section A8.8.26, encoding A1:
1432 // blx<c> <Rm>
1433 //
1434 // cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed)
1435 // and mmmm=Rm.
1436 constexpr const char *BlxName = "Blx";
1437 IValueT Rm = encodeGPRegister(Target, "Rm", BlxName);
1438 verifyRegNotPc(Rm, "Rm", BlxName);
1439 constexpr CondARM32::Cond Cond = CondARM32::AL;
1440 int32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | B21 |
1441 (0xfff << 8) | B5 | B4 | (Rm << kRmShift);
1442 emitInst(Encoding);
1443 }
1444
bx(RegARM32::GPRRegister Rm,CondARM32::Cond Cond)1445 void AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
1446 // BX - ARM section A8.8.27, encoding A1:
1447 // bx<c> <Rm>
1448 //
1449 // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
1450 assert(CondARM32::isDefined(Cond));
1451 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B24 |
1452 B21 | (0xfff << 8) | B4 |
1453 (encodeGPRRegister(Rm) << kRmShift);
1454 emitInst(Encoding);
1455 }
1456
clz(const Operand * OpRd,const Operand * OpSrc,CondARM32::Cond Cond)1457 void AssemblerARM32::clz(const Operand *OpRd, const Operand *OpSrc,
1458 CondARM32::Cond Cond) {
1459 // CLZ - ARM section A8.8.33, encoding A1:
1460 // clz<c> <Rd> <Rm>
1461 //
1462 // cccc000101101111dddd11110001mmmm where cccc=Cond, dddd=Rd, and mmmm=Rm.
1463 constexpr const char *ClzName = "clz";
1464 constexpr const char *RdName = "Rd";
1465 constexpr const char *RmName = "Rm";
1466 IValueT Rd = encodeGPRegister(OpRd, RdName, ClzName);
1467 assert(Rd < RegARM32::getNumGPRegs());
1468 verifyRegNotPc(Rd, RdName, ClzName);
1469 IValueT Rm = encodeGPRegister(OpSrc, RmName, ClzName);
1470 assert(Rm < RegARM32::getNumGPRegs());
1471 verifyRegNotPc(Rm, RmName, ClzName);
1472 assert(CondARM32::isDefined(Cond));
1473 constexpr IValueT PredefinedBits =
1474 B24 | B22 | B21 | (0xF << 16) | (0xf << 8) | B4;
1475 const IValueT Encoding = PredefinedBits | (Cond << kConditionShift) |
1476 (Rd << kRdShift) | (Rm << kRmShift);
1477 emitInst(Encoding);
1478 }
1479
cmn(const Operand * OpRn,const Operand * OpSrc1,CondARM32::Cond Cond)1480 void AssemblerARM32::cmn(const Operand *OpRn, const Operand *OpSrc1,
1481 CondARM32::Cond Cond) {
1482 // CMN (immediate) - ARM section A8.8.34, encoding A1:
1483 // cmn<c> <Rn>, #<RotatedImm8>
1484 //
1485 // cccc00110111nnnn0000iiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
1486 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1487 //
1488 // CMN (register) - ARM section A8.8.35, encodeing A1:
1489 // cmn<c> <Rn>, <Rm>{, <shift>}
1490 //
1491 // cccc00010111nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm,
1492 // iiiii=Shift, and tt=ShiftKind.
1493 constexpr const char *CmnName = "cmn";
1494 constexpr IValueT CmnOpcode = B3 | B1 | B0; // ie. 1011
1495 emitCompareOp(Cond, CmnOpcode, OpRn, OpSrc1, CmnName);
1496 }
1497
cmp(const Operand * OpRn,const Operand * OpSrc1,CondARM32::Cond Cond)1498 void AssemblerARM32::cmp(const Operand *OpRn, const Operand *OpSrc1,
1499 CondARM32::Cond Cond) {
1500 // CMP (register) - ARM section A8.8.38, encoding A1:
1501 // cmp<c> <Rn>, <Rm>{, <shift>}
1502 //
1503 // cccc00010101nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm,
1504 // iiiii=Shift, and tt=ShiftKind.
1505 //
1506 // CMP (immediate) - ARM section A8.8.37
1507 // cmp<c: <Rn>, #<RotatedImm8>
1508 //
1509 // cccc00110101nnnn0000iiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
1510 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1511 constexpr const char *CmpName = "cmp";
1512 constexpr IValueT CmpOpcode = B3 | B1; // ie. 1010
1513 emitCompareOp(Cond, CmpOpcode, OpRn, OpSrc1, CmpName);
1514 }
1515
dmb(IValueT Option)1516 void AssemblerARM32::dmb(IValueT Option) {
1517 // DMB - ARM section A8.8.43, encoding A1:
1518 // dmb <option>
1519 //
1520 // 1111010101111111111100000101xxxx where xxxx=Option.
1521 assert(Utils::IsUint(4, Option) && "Bad dmb option");
1522 const IValueT Encoding =
1523 (encodeCondition(CondARM32::kNone) << kConditionShift) | B26 | B24 | B22 |
1524 B21 | B20 | B19 | B18 | B17 | B16 | B15 | B14 | B13 | B12 | B6 | B4 |
1525 Option;
1526 emitInst(Encoding);
1527 }
1528
eor(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1529 void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn,
1530 const Operand *OpSrc1, bool SetFlags,
1531 CondARM32::Cond Cond) {
1532 // EOR (register) - ARM section A*.8.47, encoding A1:
1533 // eor{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
1534 //
1535 // cccc0000001snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
1536 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
1537 //
1538 // EOR (Immediate) - ARM section A8.*.46, encoding A1:
1539 // eor{s}<c> <Rd>, <Rn>, #RotatedImm8
1540 //
1541 // cccc0010001snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
1542 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1543 constexpr const char *EorName = "eor";
1544 constexpr IValueT EorOpcode = B0; // 0001
1545 emitType01(Cond, EorOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
1546 EorName);
1547 }
1548
ldr(const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)1549 void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
1550 CondARM32::Cond Cond, const TargetInfo &TInfo) {
1551 constexpr const char *LdrName = "ldr";
1552 constexpr bool IsLoad = true;
1553 IValueT Rt = encodeGPRegister(OpRt, "Rt", LdrName);
1554 const Type Ty = OpRt->getType();
1555 switch (Ty) {
1556 case IceType_i64:
1557 // LDRD is not implemented because target lowering handles i64 and double by
1558 // using two (32-bit) load instructions. Note: Intentionally drop to default
1559 // case.
1560 llvm::report_fatal_error(std::string("ldr : Type ") + typeString(Ty) +
1561 " not implemented");
1562 default:
1563 llvm::report_fatal_error(std::string("ldr : Type ") + typeString(Ty) +
1564 " not allowed");
1565 case IceType_i1:
1566 case IceType_i8: {
1567 // LDRB (immediate) - ARM section A8.8.68, encoding A1:
1568 // ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
1569 // ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
1570 // ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
1571 //
1572 // cccc010pu1w1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
1573 // iiiiiiiiiiii=imm12, u=1 if +, pu0w is a BlockAddr, and
1574 // pu0w0nnnn0000iiiiiiiiiiii=Address.
1575 //
1576 // LDRB (register) - ARM section A8.8.66, encoding A1:
1577 // ldrb<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
1578 // ldrb<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
1579 //
1580 // cccc011pu1w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b
1581 // is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address.
1582 constexpr bool IsByte = true;
1583 emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, LdrName);
1584 return;
1585 }
1586 case IceType_i16: {
1587 // LDRH (immediate) - ARM section A8.8.80, encoding A1:
1588 // ldrh<c> <Rt>, [<Rn>{, #+/-<Imm8>}]
1589 // ldrh<c> <Rt>, [<Rn>], #+/-<Imm8>
1590 // ldrh<c> <Rt>, [<Rn>, #+/-<Imm8>]!
1591 //
1592 // cccc000pu1w1nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn,
1593 // iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and
1594 // pu0w0nnnn0000iiiiiiiiiiii=Address.
1595 constexpr const char *Ldrh = "ldrh";
1596 emitMemOpEnc3(Cond, L | B7 | B5 | B4, Rt, OpAddress, TInfo, Ldrh);
1597 return;
1598 }
1599 case IceType_i32: {
1600 // LDR (immediate) - ARM section A8.8.63, encoding A1:
1601 // ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
1602 // ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
1603 // ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
1604 //
1605 // cccc010pu0w1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
1606 // iiiiiiiiiiii=imm12, u=1 if +, pu0w is a BlockAddr, and
1607 //
1608 // LDR (register) - ARM section A8.8.70, encoding A1:
1609 // ldrb<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
1610 // ldrb<c> <Rt>, [<Rn>], +-<Rm>{, <shift>}
1611 //
1612 // cccc011pu0w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b
1613 // is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address.
1614 constexpr bool IsByte = false;
1615 emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, LdrName);
1616 return;
1617 }
1618 }
1619 }
1620
emitMemExOp(CondARM32::Cond Cond,Type Ty,bool IsLoad,const Operand * OpRd,IValueT Rt,const Operand * OpAddress,const TargetInfo & TInfo,const char * InstName)1621 void AssemblerARM32::emitMemExOp(CondARM32::Cond Cond, Type Ty, bool IsLoad,
1622 const Operand *OpRd, IValueT Rt,
1623 const Operand *OpAddress,
1624 const TargetInfo &TInfo,
1625 const char *InstName) {
1626 IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
1627 IValueT MemExOpcode = IsLoad ? B0 : 0;
1628 switch (Ty) {
1629 default:
1630 llvm::report_fatal_error(std::string(InstName) + ": Type " +
1631 typeString(Ty) + " not allowed");
1632 case IceType_i1:
1633 case IceType_i8:
1634 MemExOpcode |= B2;
1635 break;
1636 case IceType_i16:
1637 MemExOpcode |= B2 | B1;
1638 break;
1639 case IceType_i32:
1640 break;
1641 case IceType_i64:
1642 MemExOpcode |= B1;
1643 }
1644 IValueT AddressRn;
1645 if (encodeAddress(OpAddress, AddressRn, TInfo, NoImmOffsetAddress) !=
1646 EncodedAsImmRegOffset)
1647 llvm::report_fatal_error(std::string(InstName) +
1648 ": Can't extract Rn from address");
1649 assert(Utils::IsAbsoluteUint(3, MemExOpcode));
1650 assert(Rd < RegARM32::getNumGPRegs());
1651 assert(Rt < RegARM32::getNumGPRegs());
1652 assert(CondARM32::isDefined(Cond));
1653 IValueT Encoding = (Cond << kConditionShift) | B24 | B23 | B11 | B10 | B9 |
1654 B8 | B7 | B4 | (MemExOpcode << kMemExOpcodeShift) |
1655 AddressRn | (Rd << kRdShift) | (Rt << kRmShift);
1656 emitInst(Encoding);
1657 return;
1658 }
1659
ldrex(const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)1660 void AssemblerARM32::ldrex(const Operand *OpRt, const Operand *OpAddress,
1661 CondARM32::Cond Cond, const TargetInfo &TInfo) {
1662 // LDREXB - ARM section A8.8.76, encoding A1:
1663 // ldrexb<c> <Rt>, [<Rn>]
1664 //
1665 // cccc00011101nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
1666 //
1667 // LDREXH - ARM section A8.8.78, encoding A1:
1668 // ldrexh<c> <Rt>, [<Rn>]
1669 //
1670 // cccc00011111nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
1671 //
1672 // LDREX - ARM section A8.8.75, encoding A1:
1673 // ldrex<c> <Rt>, [<Rn>]
1674 //
1675 // cccc00011001nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
1676 //
1677 // LDREXD - ARM section A8.
1678 // ldrexd<c> <Rt>, [<Rn>]
1679 //
1680 // cccc00011001nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
1681 constexpr const char *LdrexName = "ldrex";
1682 const Type Ty = OpRt->getType();
1683 constexpr bool IsLoad = true;
1684 constexpr IValueT Rm = RegARM32::Encoded_Reg_pc;
1685 emitMemExOp(Cond, Ty, IsLoad, OpRt, Rm, OpAddress, TInfo, LdrexName);
1686 }
1687
emitShift(const CondARM32::Cond Cond,const OperandARM32::ShiftKind Shift,const Operand * OpRd,const Operand * OpRm,const Operand * OpSrc1,const bool SetFlags,const char * InstName)1688 void AssemblerARM32::emitShift(const CondARM32::Cond Cond,
1689 const OperandARM32::ShiftKind Shift,
1690 const Operand *OpRd, const Operand *OpRm,
1691 const Operand *OpSrc1, const bool SetFlags,
1692 const char *InstName) {
1693 constexpr IValueT ShiftOpcode = B3 | B2 | B0; // 1101
1694 IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
1695 IValueT Rm = encodeGPRegister(OpRm, "Rm", InstName);
1696 IValueT Value;
1697 switch (encodeOperand(OpSrc1, Value, WantGPRegs)) {
1698 default:
1699 llvm::report_fatal_error(std::string(InstName) +
1700 ": Last operand not understood");
1701 case EncodedAsShiftImm5: {
1702 // XXX (immediate)
1703 // xxx{s}<c> <Rd>, <Rm>, #imm5
1704 //
1705 // cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
1706 // iiiii=imm5, and mmmm=Rm.
1707 constexpr IValueT Rn = 0; // Rn field is not used.
1708 Value = Value | (Rm << kRmShift) | (Shift << kShiftShift);
1709 emitType01(Cond, kInstTypeDataRegShift, ShiftOpcode, SetFlags, Rn, Rd,
1710 Value, RdIsPcAndSetFlags, InstName);
1711 return;
1712 }
1713 case EncodedAsRegister: {
1714 // XXX (register)
1715 // xxx{S}<c> <Rd>, <Rm>, <Rs>
1716 //
1717 // cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
1718 // mmmm=Rm, and ssss=Rs.
1719 constexpr IValueT Rn = 0; // Rn field is not used.
1720 IValueT Rs = encodeGPRegister(OpSrc1, "Rs", InstName);
1721 verifyRegNotPc(Rd, "Rd", InstName);
1722 verifyRegNotPc(Rm, "Rm", InstName);
1723 verifyRegNotPc(Rs, "Rs", InstName);
1724 emitType01(Cond, kInstTypeDataRegShift, ShiftOpcode, SetFlags, Rn, Rd,
1725 encodeShiftRotateReg(Rm, Shift, Rs), NoChecks, InstName);
1726 return;
1727 }
1728 }
1729 }
1730
asr(const Operand * OpRd,const Operand * OpRm,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1731 void AssemblerARM32::asr(const Operand *OpRd, const Operand *OpRm,
1732 const Operand *OpSrc1, bool SetFlags,
1733 CondARM32::Cond Cond) {
1734 constexpr const char *AsrName = "asr";
1735 emitShift(Cond, OperandARM32::ASR, OpRd, OpRm, OpSrc1, SetFlags, AsrName);
1736 }
1737
lsl(const Operand * OpRd,const Operand * OpRm,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1738 void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm,
1739 const Operand *OpSrc1, bool SetFlags,
1740 CondARM32::Cond Cond) {
1741 constexpr const char *LslName = "lsl";
1742 emitShift(Cond, OperandARM32::LSL, OpRd, OpRm, OpSrc1, SetFlags, LslName);
1743 }
1744
lsr(const Operand * OpRd,const Operand * OpRm,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1745 void AssemblerARM32::lsr(const Operand *OpRd, const Operand *OpRm,
1746 const Operand *OpSrc1, bool SetFlags,
1747 CondARM32::Cond Cond) {
1748 constexpr const char *LsrName = "lsr";
1749 emitShift(Cond, OperandARM32::LSR, OpRd, OpRm, OpSrc1, SetFlags, LsrName);
1750 }
1751
mov(const Operand * OpRd,const Operand * OpSrc,CondARM32::Cond Cond)1752 void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
1753 CondARM32::Cond Cond) {
1754 // MOV (register) - ARM section A8.8.104, encoding A1:
1755 // mov{S}<c> <Rd>, <Rn>
1756 //
1757 // cccc0001101s0000dddd00000000mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
1758 // and nnnn=Rn.
1759 //
1760 // MOV (immediate) - ARM section A8.8.102, encoding A1:
1761 // mov{S}<c> <Rd>, #<RotatedImm8>
1762 //
1763 // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd,
1764 // and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this
1765 // assembler.
1766 constexpr const char *MovName = "mov";
1767 IValueT Rd = encodeGPRegister(OpRd, "Rd", MovName);
1768 constexpr bool SetFlags = false;
1769 constexpr IValueT Rn = 0;
1770 constexpr IValueT MovOpcode = B3 | B2 | B0; // 1101.
1771 emitType01(Cond, MovOpcode, Rd, Rn, OpSrc, SetFlags, RdIsPcAndSetFlags,
1772 MovName);
1773 }
1774
emitMovwt(CondARM32::Cond Cond,bool IsMovW,const Operand * OpRd,const Operand * OpSrc,const char * MovName)1775 void AssemblerARM32::emitMovwt(CondARM32::Cond Cond, bool IsMovW,
1776 const Operand *OpRd, const Operand *OpSrc,
1777 const char *MovName) {
1778 IValueT Opcode = B25 | B24 | (IsMovW ? 0 : B22);
1779 IValueT Rd = encodeGPRegister(OpRd, "Rd", MovName);
1780 IValueT Imm16;
1781 if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) {
1782 emitFixup(createMoveFixup(IsMovW, Src));
1783 // Use 0 for the lower 16 bits of the relocatable, and add a fixup to
1784 // install the correct bits.
1785 Imm16 = 0;
1786 } else if (encodeOperand(OpSrc, Imm16, WantGPRegs) != EncodedAsConstI32) {
1787 llvm::report_fatal_error(std::string(MovName) + ": Not i32 constant");
1788 }
1789 assert(CondARM32::isDefined(Cond));
1790 if (!Utils::IsAbsoluteUint(16, Imm16))
1791 llvm::report_fatal_error(std::string(MovName) + ": Constant not i16");
1792 const IValueT Encoding = encodeCondition(Cond) << kConditionShift | Opcode |
1793 ((Imm16 >> 12) << 16) | Rd << kRdShift |
1794 (Imm16 & 0xfff);
1795 emitInst(Encoding);
1796 }
1797
movw(const Operand * OpRd,const Operand * OpSrc,CondARM32::Cond Cond)1798 void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc,
1799 CondARM32::Cond Cond) {
1800 // MOV (immediate) - ARM section A8.8.102, encoding A2:
1801 // movw<c> <Rd>, #<imm16>
1802 //
1803 // cccc00110000iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and
1804 // iiiiiiiiiiiiiiii=imm16.
1805 constexpr const char *MovwName = "movw";
1806 constexpr bool IsMovW = true;
1807 emitMovwt(Cond, IsMovW, OpRd, OpSrc, MovwName);
1808 }
1809
movt(const Operand * OpRd,const Operand * OpSrc,CondARM32::Cond Cond)1810 void AssemblerARM32::movt(const Operand *OpRd, const Operand *OpSrc,
1811 CondARM32::Cond Cond) {
1812 // MOVT - ARM section A8.8.106, encoding A1:
1813 // movt<c> <Rd>, #<imm16>
1814 //
1815 // cccc00110100iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and
1816 // iiiiiiiiiiiiiiii=imm16.
1817 constexpr const char *MovtName = "movt";
1818 constexpr bool IsMovW = false;
1819 emitMovwt(Cond, IsMovW, OpRd, OpSrc, MovtName);
1820 }
1821
mvn(const Operand * OpRd,const Operand * OpSrc,CondARM32::Cond Cond)1822 void AssemblerARM32::mvn(const Operand *OpRd, const Operand *OpSrc,
1823 CondARM32::Cond Cond) {
1824 // MVN (immediate) - ARM section A8.8.115, encoding A1:
1825 // mvn{s}<c> <Rd>, #<const>
1826 //
1827 // cccc0011111s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags=0, dddd=Rd,
1828 // and iiiiiiiiiiii=const
1829 //
1830 // MVN (register) - ARM section A8.8.116, encoding A1:
1831 // mvn{s}<c> <Rd>, <Rm>{, <shift>
1832 //
1833 // cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd,
1834 // mmmm=Rm, iiii defines shift constant, and tt=ShiftKind.
1835 constexpr const char *MvnName = "mvn";
1836 IValueT Rd = encodeGPRegister(OpRd, "Rd", MvnName);
1837 constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111
1838 constexpr IValueT Rn = 0;
1839 constexpr bool SetFlags = false;
1840 emitType01(Cond, MvnOpcode, Rd, Rn, OpSrc, SetFlags, RdIsPcAndSetFlags,
1841 MvnName);
1842 }
1843
nop()1844 void AssemblerARM32::nop() {
1845 // NOP - Section A8.8.119, encoding A1:
1846 // nop<c>
1847 //
1848 // cccc0011001000001111000000000000 where cccc=Cond.
1849 constexpr CondARM32::Cond Cond = CondARM32::AL;
1850 const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B25 |
1851 B24 | B21 | B15 | B14 | B13 | B12;
1852 emitInst(Encoding);
1853 }
1854
sbc(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1855 void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
1856 const Operand *OpSrc1, bool SetFlags,
1857 CondARM32::Cond Cond) {
1858 // SBC (register) - ARM section 18.8.162, encoding A1:
1859 // sbc{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
1860 //
1861 // cccc0000110snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
1862 // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
1863 //
1864 // SBC (Immediate) - ARM section A8.8.161, encoding A1:
1865 // sbc{s}<c> <Rd>, <Rn>, #<RotatedImm8>
1866 //
1867 // cccc0010110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
1868 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
1869 constexpr const char *SbcName = "sbc";
1870 constexpr IValueT SbcOpcode = B2 | B1; // 0110
1871 emitType01(Cond, SbcOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
1872 SbcName);
1873 }
1874
sdiv(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,CondARM32::Cond Cond)1875 void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn,
1876 const Operand *OpSrc1, CondARM32::Cond Cond) {
1877 // SDIV - ARM section A8.8.165, encoding A1.
1878 // sdiv<c> <Rd>, <Rn>, <Rm>
1879 //
1880 // cccc01110001dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
1881 // mmmm=Rm.
1882 constexpr const char *SdivName = "sdiv";
1883 IValueT Rd = encodeGPRegister(OpRd, "Rd", SdivName);
1884 IValueT Rn = encodeGPRegister(OpRn, "Rn", SdivName);
1885 IValueT Rm = encodeGPRegister(OpSrc1, "Rm", SdivName);
1886 verifyRegNotPc(Rd, "Rd", SdivName);
1887 verifyRegNotPc(Rn, "Rn", SdivName);
1888 verifyRegNotPc(Rm, "Rm", SdivName);
1889 // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
1890 constexpr IValueT SdivOpcode = 0;
1891 emitDivOp(Cond, SdivOpcode, Rd, Rn, Rm);
1892 }
1893
str(const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)1894 void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
1895 CondARM32::Cond Cond, const TargetInfo &TInfo) {
1896 constexpr const char *StrName = "str";
1897 constexpr bool IsLoad = false;
1898 IValueT Rt = encodeGPRegister(OpRt, "Rt", StrName);
1899 const Type Ty = OpRt->getType();
1900 switch (Ty) {
1901 case IceType_i64:
1902 // STRD is not implemented because target lowering handles i64 and double by
1903 // using two (32-bit) store instructions. Note: Intentionally drop to
1904 // default case.
1905 llvm::report_fatal_error(std::string(StrName) + ": Type " + typeString(Ty) +
1906 " not implemented");
1907 default:
1908 llvm::report_fatal_error(std::string(StrName) + ": Type " + typeString(Ty) +
1909 " not allowed");
1910 case IceType_i1:
1911 case IceType_i8: {
1912 // STRB (immediate) - ARM section A8.8.207, encoding A1:
1913 // strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
1914 // strb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
1915 // strb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
1916 //
1917 // cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
1918 // iiiiiiiiiiii=imm12, u=1 if +.
1919 constexpr bool IsByte = true;
1920 emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, StrName);
1921 return;
1922 }
1923 case IceType_i16: {
1924 // STRH (immediate) - ARM section A8.*.217, encoding A1:
1925 // strh<c> <Rt>, [<Rn>{, #+/-<Imm8>}]
1926 // strh<c> <Rt>, [<Rn>], #+/-<Imm8>
1927 // strh<c> <Rt>, [<Rn>, #+/-<Imm8>]!
1928 //
1929 // cccc000pu1w0nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn,
1930 // iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and
1931 // pu0w0nnnn0000iiiiiiiiiiii=Address.
1932 constexpr const char *Strh = "strh";
1933 emitMemOpEnc3(Cond, B7 | B5 | B4, Rt, OpAddress, TInfo, Strh);
1934 return;
1935 }
1936 case IceType_i32: {
1937 // Note: Handles i32 and float stores. Target lowering handles i64 and
1938 // double by using two (32 bit) store instructions.
1939 //
1940 // STR (immediate) - ARM section A8.8.207, encoding A1:
1941 // str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
1942 // str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
1943 // str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
1944 //
1945 // cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
1946 // iiiiiiiiiiii=imm12, u=1 if +.
1947 constexpr bool IsByte = false;
1948 emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, StrName);
1949 return;
1950 }
1951 }
1952 }
1953
strex(const Operand * OpRd,const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)1954 void AssemblerARM32::strex(const Operand *OpRd, const Operand *OpRt,
1955 const Operand *OpAddress, CondARM32::Cond Cond,
1956 const TargetInfo &TInfo) {
1957 // STREXB - ARM section A8.8.213, encoding A1:
1958 // strexb<c> <Rd>, <Rt>, [<Rn>]
1959 //
1960 // cccc00011100nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
1961 // nnnn=Rn.
1962 //
1963 // STREXH - ARM section A8.8.215, encoding A1:
1964 // strexh<c> <Rd>, <Rt>, [<Rn>]
1965 //
1966 // cccc00011110nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
1967 // nnnn=Rn.
1968 //
1969 // STREX - ARM section A8.8.212, encoding A1:
1970 // strex<c> <Rd>, <Rt>, [<Rn>]
1971 //
1972 // cccc00011000nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
1973 // nnnn=Rn.
1974 //
1975 // STREXD - ARM section A8.8.214, encoding A1:
1976 // strexd<c> <Rd>, <Rt>, [<Rn>]
1977 //
1978 // cccc00011010nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
1979 // nnnn=Rn.
1980 constexpr const char *StrexName = "strex";
1981 // Note: Rt uses Rm shift in encoding.
1982 IValueT Rt = encodeGPRegister(OpRt, "Rt", StrexName);
1983 const Type Ty = OpRt->getType();
1984 constexpr bool IsLoad = true;
1985 emitMemExOp(Cond, Ty, !IsLoad, OpRd, Rt, OpAddress, TInfo, StrexName);
1986 }
1987
orr(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)1988 void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
1989 const Operand *OpSrc1, bool SetFlags,
1990 CondARM32::Cond Cond) {
1991 // ORR (register) - ARM Section A8.8.123, encoding A1:
1992 // orr{s}<c> <Rd>, <Rn>, <Rm>
1993 //
1994 // cccc0001100snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
1995 // mmmm=Rm, iiiii=shift, tt=ShiftKind,, and s=SetFlags.
1996 //
1997 // ORR (register) - ARM Section A8.8.123, encoding A1:
1998 // orr{s}<c> <Rd>, <Rn>, #<RotatedImm8>
1999 //
2000 // cccc0001100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
2001 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
2002 constexpr const char *OrrName = "orr";
2003 constexpr IValueT OrrOpcode = B3 | B2; // i.e. 1100
2004 emitType01(Cond, OrrOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
2005 OrrName);
2006 }
2007
pop(const Variable * OpRt,CondARM32::Cond Cond)2008 void AssemblerARM32::pop(const Variable *OpRt, CondARM32::Cond Cond) {
2009 // POP - ARM section A8.8.132, encoding A2:
2010 // pop<c> {Rt}
2011 //
2012 // cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond.
2013 constexpr const char *Pop = "pop";
2014 IValueT Rt = encodeGPRegister(OpRt, "Rt", Pop);
2015 verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Pop);
2016 // Same as load instruction.
2017 constexpr bool IsLoad = true;
2018 constexpr bool IsByte = false;
2019 constexpr IOffsetT MaxOffset = (1 << 8) - 1;
2020 constexpr IValueT NoShiftRight = 0;
2021 IValueT Address =
2022 encodeImmRegOffset(RegARM32::Encoded_Reg_sp, kWordSize,
2023 OperandARM32Mem::PostIndex, MaxOffset, NoShiftRight);
2024 emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
2025 }
2026
popList(const IValueT Registers,CondARM32::Cond Cond)2027 void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) {
2028 // POP - ARM section A8.*.131, encoding A1:
2029 // pop<c> <registers>
2030 //
2031 // cccc100010111101rrrrrrrrrrrrrrrr where cccc=Cond and
2032 // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
2033 constexpr bool IsLoad = true;
2034 emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers);
2035 }
2036
push(const Operand * OpRt,CondARM32::Cond Cond)2037 void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
2038 // PUSH - ARM section A8.8.133, encoding A2:
2039 // push<c> {Rt}
2040 //
2041 // cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond.
2042 constexpr const char *Push = "push";
2043 IValueT Rt = encodeGPRegister(OpRt, "Rt", Push);
2044 verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Push);
2045 // Same as store instruction.
2046 constexpr bool isLoad = false;
2047 constexpr bool isByte = false;
2048 constexpr IOffsetT MaxOffset = (1 << 8) - 1;
2049 constexpr IValueT NoShiftRight = 0;
2050 IValueT Address =
2051 encodeImmRegOffset(RegARM32::Encoded_Reg_sp, -kWordSize,
2052 OperandARM32Mem::PreIndex, MaxOffset, NoShiftRight);
2053 emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address);
2054 }
2055
pushList(const IValueT Registers,CondARM32::Cond Cond)2056 void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) {
2057 // PUSH - ARM section A8.8.133, encoding A1:
2058 // push<c> <Registers>
2059 //
2060 // cccc100100101101rrrrrrrrrrrrrrrr where cccc=Cond and
2061 // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
2062 constexpr bool IsLoad = false;
2063 emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers);
2064 }
2065
mla(const Operand * OpRd,const Operand * OpRn,const Operand * OpRm,const Operand * OpRa,CondARM32::Cond Cond)2066 void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn,
2067 const Operand *OpRm, const Operand *OpRa,
2068 CondARM32::Cond Cond) {
2069 // MLA - ARM section A8.8.114, encoding A1.
2070 // mla{s}<c> <Rd>, <Rn>, <Rm>, <Ra>
2071 //
2072 // cccc0000001sddddaaaammmm1001nnnn where cccc=Cond, s=SetFlags, dddd=Rd,
2073 // aaaa=Ra, mmmm=Rm, and nnnn=Rn.
2074 constexpr const char *MlaName = "mla";
2075 IValueT Rd = encodeGPRegister(OpRd, "Rd", MlaName);
2076 IValueT Rn = encodeGPRegister(OpRn, "Rn", MlaName);
2077 IValueT Rm = encodeGPRegister(OpRm, "Rm", MlaName);
2078 IValueT Ra = encodeGPRegister(OpRa, "Ra", MlaName);
2079 verifyRegNotPc(Rd, "Rd", MlaName);
2080 verifyRegNotPc(Rn, "Rn", MlaName);
2081 verifyRegNotPc(Rm, "Rm", MlaName);
2082 verifyRegNotPc(Ra, "Ra", MlaName);
2083 constexpr IValueT MlaOpcode = B21;
2084 constexpr bool SetFlags = true;
2085 // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
2086 emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, !SetFlags);
2087 }
2088
mls(const Operand * OpRd,const Operand * OpRn,const Operand * OpRm,const Operand * OpRa,CondARM32::Cond Cond)2089 void AssemblerARM32::mls(const Operand *OpRd, const Operand *OpRn,
2090 const Operand *OpRm, const Operand *OpRa,
2091 CondARM32::Cond Cond) {
2092 constexpr const char *MlsName = "mls";
2093 IValueT Rd = encodeGPRegister(OpRd, "Rd", MlsName);
2094 IValueT Rn = encodeGPRegister(OpRn, "Rn", MlsName);
2095 IValueT Rm = encodeGPRegister(OpRm, "Rm", MlsName);
2096 IValueT Ra = encodeGPRegister(OpRa, "Ra", MlsName);
2097 verifyRegNotPc(Rd, "Rd", MlsName);
2098 verifyRegNotPc(Rn, "Rn", MlsName);
2099 verifyRegNotPc(Rm, "Rm", MlsName);
2100 verifyRegNotPc(Ra, "Ra", MlsName);
2101 constexpr IValueT MlsOpcode = B22 | B21;
2102 constexpr bool SetFlags = true;
2103 // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
2104 emitMulOp(Cond, MlsOpcode, Ra, Rd, Rn, Rm, !SetFlags);
2105 }
2106
mul(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)2107 void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn,
2108 const Operand *OpSrc1, bool SetFlags,
2109 CondARM32::Cond Cond) {
2110 // MUL - ARM section A8.8.114, encoding A1.
2111 // mul{s}<c> <Rd>, <Rn>, <Rm>
2112 //
2113 // cccc0000000sdddd0000mmmm1001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn,
2114 // mmmm=Rm, and s=SetFlags.
2115 constexpr const char *MulName = "mul";
2116 IValueT Rd = encodeGPRegister(OpRd, "Rd", MulName);
2117 IValueT Rn = encodeGPRegister(OpRn, "Rn", MulName);
2118 IValueT Rm = encodeGPRegister(OpSrc1, "Rm", MulName);
2119 verifyRegNotPc(Rd, "Rd", MulName);
2120 verifyRegNotPc(Rn, "Rn", MulName);
2121 verifyRegNotPc(Rm, "Rm", MulName);
2122 // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
2123 constexpr IValueT MulOpcode = 0;
2124 emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags);
2125 }
2126
emitRdRm(CondARM32::Cond Cond,IValueT Opcode,const Operand * OpRd,const Operand * OpRm,const char * InstName)2127 void AssemblerARM32::emitRdRm(CondARM32::Cond Cond, IValueT Opcode,
2128 const Operand *OpRd, const Operand *OpRm,
2129 const char *InstName) {
2130 IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
2131 IValueT Rm = encodeGPRegister(OpRm, "Rm", InstName);
2132 IValueT Encoding =
2133 (Cond << kConditionShift) | Opcode | (Rd << kRdShift) | (Rm << kRmShift);
2134 emitInst(Encoding);
2135 }
2136
rbit(const Operand * OpRd,const Operand * OpRm,CondARM32::Cond Cond)2137 void AssemblerARM32::rbit(const Operand *OpRd, const Operand *OpRm,
2138 CondARM32::Cond Cond) {
2139 // RBIT - ARM section A8.8.144, encoding A1:
2140 // rbit<c> <Rd>, <Rm>
2141 //
2142 // cccc011011111111dddd11110011mmmm where cccc=Cond, dddd=Rn, and mmmm=Rm.
2143 constexpr const char *RbitName = "rev";
2144 constexpr IValueT RbitOpcode = B26 | B25 | B23 | B22 | B21 | B20 | B19 | B18 |
2145 B17 | B16 | B11 | B10 | B9 | B8 | B5 | B4;
2146 emitRdRm(Cond, RbitOpcode, OpRd, OpRm, RbitName);
2147 }
2148
rev(const Operand * OpRd,const Operand * OpRm,CondARM32::Cond Cond)2149 void AssemblerARM32::rev(const Operand *OpRd, const Operand *OpRm,
2150 CondARM32::Cond Cond) {
2151 // REV - ARM section A8.8.145, encoding A1:
2152 // rev<c> <Rd>, <Rm>
2153 //
2154 // cccc011010111111dddd11110011mmmm where cccc=Cond, dddd=Rn, and mmmm=Rm.
2155 constexpr const char *RevName = "rev";
2156 constexpr IValueT RevOpcode = B26 | B25 | B23 | B21 | B20 | B19 | B18 | B17 |
2157 B16 | B11 | B10 | B9 | B8 | B5 | B4;
2158 emitRdRm(Cond, RevOpcode, OpRd, OpRm, RevName);
2159 }
2160
rsb(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)2161 void AssemblerARM32::rsb(const Operand *OpRd, const Operand *OpRn,
2162 const Operand *OpSrc1, bool SetFlags,
2163 CondARM32::Cond Cond) {
2164 // RSB (immediate) - ARM section A8.8.152, encoding A1.
2165 // rsb{s}<c> <Rd>, <Rn>, #<RotatedImm8>
2166 //
2167 // cccc0010011snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
2168 // s=setFlags and iiiiiiiiiiii defines the RotatedImm8 value.
2169 //
2170 // RSB (register) - ARM section A8.8.163, encoding A1.
2171 // rsb{s}<c> <Rd>, <Rn>, <Rm>{, <Shift>}
2172 //
2173 // cccc0000011snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
2174 // mmmm=Rm, iiiii=shift, tt==ShiftKind, and s=SetFlags.
2175 constexpr const char *RsbName = "rsb";
2176 constexpr IValueT RsbOpcode = B1 | B0; // 0011
2177 emitType01(Cond, RsbOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
2178 RsbName);
2179 }
2180
rsc(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)2181 void AssemblerARM32::rsc(const Operand *OpRd, const Operand *OpRn,
2182 const Operand *OpSrc1, bool SetFlags,
2183 CondARM32::Cond Cond) {
2184 // RSC (immediate) - ARM section A8.8.155, encoding A1:
2185 // rsc{s}<c> <Rd>, <Rn>, #<RotatedImm8>
2186 //
2187 // cccc0010111snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
2188 // mmmm=Rm, iiiii=shift, tt=ShiftKind, and s=SetFlags.
2189 //
2190 // RSC (register) - ARM section A8.8.156, encoding A1:
2191 // rsc{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
2192 //
2193 // cccc0000111snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
2194 // mmmm=Rm, iiiii=shift, tt=ShiftKind, and s=SetFlags.
2195 //
2196 // RSC (register-shifted register) - ARM section A8.8.157, encoding A1:
2197 // rsc{s}<c> <Rd>, <Rn>, <Rm>, <type> <Rs>
2198 //
2199 // cccc0000111fnnnnddddssss0tt1mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
2200 // mmmm=Rm, ssss=Rs, tt defined <type>, and f=SetFlags.
2201 constexpr const char *RscName = "rsc";
2202 constexpr IValueT RscOpcode = B2 | B1 | B0; // i.e. 0111.
2203 emitType01(Cond, RscOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
2204 RscName);
2205 }
2206
sxt(const Operand * OpRd,const Operand * OpSrc0,CondARM32::Cond Cond)2207 void AssemblerARM32::sxt(const Operand *OpRd, const Operand *OpSrc0,
2208 CondARM32::Cond Cond) {
2209 constexpr const char *SxtName = "sxt";
2210 constexpr IValueT SxtOpcode = B26 | B25 | B23 | B21;
2211 emitSignExtend(Cond, SxtOpcode, OpRd, OpSrc0, SxtName);
2212 }
2213
sub(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,bool SetFlags,CondARM32::Cond Cond)2214 void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
2215 const Operand *OpSrc1, bool SetFlags,
2216 CondARM32::Cond Cond) {
2217 // SUB (register) - ARM section A8.8.223, encoding A1:
2218 // sub{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
2219 // SUB (SP minus register): See ARM section 8.8.226, encoding A1:
2220 // sub{s}<c> <Rd>, sp, <Rm>{, <Shift>}
2221 //
2222 // cccc0000010snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
2223 // mmmm=Rm, iiiii=shift, tt=ShiftKind, and s=SetFlags.
2224 //
2225 // Sub (Immediate) - ARM section A8.8.222, encoding A1:
2226 // sub{s}<c> <Rd>, <Rn>, #<RotatedImm8>
2227 // Sub (Sp minus immediate) - ARM section A8.8.225, encoding A1:
2228 // sub{s}<c> sp, <Rn>, #<RotatedImm8>
2229 //
2230 // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
2231 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8
2232 constexpr const char *SubName = "sub";
2233 constexpr IValueT SubOpcode = B1; // 0010
2234 emitType01(Cond, SubOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
2235 SubName);
2236 }
2237
2238 namespace {
2239
2240 // Use a particular UDF encoding -- TRAPNaCl in LLVM: 0xE7FEDEF0
2241 // http://llvm.org/viewvc/llvm-project?view=revision&revision=173943
2242 const uint8_t TrapBytesRaw[] = {0xE7, 0xFE, 0xDE, 0xF0};
2243
2244 const auto TrapBytes =
2245 llvm::ArrayRef<uint8_t>(TrapBytesRaw, llvm::array_lengthof(TrapBytesRaw));
2246
2247 } // end of anonymous namespace
2248
getNonExecBundlePadding() const2249 llvm::ArrayRef<uint8_t> AssemblerARM32::getNonExecBundlePadding() const {
2250 return TrapBytes;
2251 }
2252
trap()2253 void AssemblerARM32::trap() {
2254 AssemblerBuffer::EnsureCapacity ensured(&Buffer);
2255 for (const uint8_t &Byte : reverse_range(TrapBytes))
2256 Buffer.emit<uint8_t>(Byte);
2257 }
2258
tst(const Operand * OpRn,const Operand * OpSrc1,CondARM32::Cond Cond)2259 void AssemblerARM32::tst(const Operand *OpRn, const Operand *OpSrc1,
2260 CondARM32::Cond Cond) {
2261 // TST (register) - ARM section A8.8.241, encoding A1:
2262 // tst<c> <Rn>, <Rm>(, <shift>}
2263 //
2264 // cccc00010001nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm,
2265 // iiiii=Shift, and tt=ShiftKind.
2266 //
2267 // TST (immediate) - ARM section A8.8.240, encoding A1:
2268 // tst<c> <Rn>, #<RotatedImm8>
2269 //
2270 // cccc00110001nnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn, and
2271 // iiiiiiiiiiii defines RotatedImm8.
2272 constexpr const char *TstName = "tst";
2273 constexpr IValueT TstOpcode = B3; // ie. 1000
2274 emitCompareOp(Cond, TstOpcode, OpRn, OpSrc1, TstName);
2275 }
2276
udiv(const Operand * OpRd,const Operand * OpRn,const Operand * OpSrc1,CondARM32::Cond Cond)2277 void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn,
2278 const Operand *OpSrc1, CondARM32::Cond Cond) {
2279 // UDIV - ARM section A8.8.248, encoding A1.
2280 // udiv<c> <Rd>, <Rn>, <Rm>
2281 //
2282 // cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
2283 // mmmm=Rm.
2284 constexpr const char *UdivName = "udiv";
2285 IValueT Rd = encodeGPRegister(OpRd, "Rd", UdivName);
2286 IValueT Rn = encodeGPRegister(OpRn, "Rn", UdivName);
2287 IValueT Rm = encodeGPRegister(OpSrc1, "Rm", UdivName);
2288 verifyRegNotPc(Rd, "Rd", UdivName);
2289 verifyRegNotPc(Rn, "Rn", UdivName);
2290 verifyRegNotPc(Rm, "Rm", UdivName);
2291 // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
2292 constexpr IValueT UdivOpcode = B21;
2293 emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm);
2294 }
2295
umull(const Operand * OpRdLo,const Operand * OpRdHi,const Operand * OpRn,const Operand * OpRm,CondARM32::Cond Cond)2296 void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
2297 const Operand *OpRn, const Operand *OpRm,
2298 CondARM32::Cond Cond) {
2299 // UMULL - ARM section A8.8.257, encoding A1:
2300 // umull<c> <RdLo>, <RdHi>, <Rn>, <Rm>
2301 //
2302 // cccc0000100shhhhllllmmmm1001nnnn where hhhh=RdHi, llll=RdLo, nnnn=Rn,
2303 // mmmm=Rm, and s=SetFlags
2304 constexpr const char *UmullName = "umull";
2305 IValueT RdLo = encodeGPRegister(OpRdLo, "RdLo", UmullName);
2306 IValueT RdHi = encodeGPRegister(OpRdHi, "RdHi", UmullName);
2307 IValueT Rn = encodeGPRegister(OpRn, "Rn", UmullName);
2308 IValueT Rm = encodeGPRegister(OpRm, "Rm", UmullName);
2309 verifyRegNotPc(RdLo, "RdLo", UmullName);
2310 verifyRegNotPc(RdHi, "RdHi", UmullName);
2311 verifyRegNotPc(Rn, "Rn", UmullName);
2312 verifyRegNotPc(Rm, "Rm", UmullName);
2313 verifyRegsNotEq(RdHi, "RdHi", RdLo, "RdLo", UmullName);
2314 constexpr IValueT UmullOpcode = B23;
2315 constexpr bool SetFlags = false;
2316 emitMulOp(Cond, UmullOpcode, RdLo, RdHi, Rn, Rm, SetFlags);
2317 }
2318
uxt(const Operand * OpRd,const Operand * OpSrc0,CondARM32::Cond Cond)2319 void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
2320 CondARM32::Cond Cond) {
2321 constexpr const char *UxtName = "uxt";
2322 constexpr IValueT UxtOpcode = B26 | B25 | B23 | B22 | B21;
2323 emitSignExtend(Cond, UxtOpcode, OpRd, OpSrc0, UxtName);
2324 }
2325
vabss(const Operand * OpSd,const Operand * OpSm,CondARM32::Cond Cond)2326 void AssemblerARM32::vabss(const Operand *OpSd, const Operand *OpSm,
2327 CondARM32::Cond Cond) {
2328 // VABS - ARM section A8.8.280, encoding A2:
2329 // vabs<c>.f32 <Sd>, <Sm>
2330 //
2331 // cccc11101D110000dddd101011M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
2332 constexpr const char *Vabss = "vabss";
2333 IValueT Sd = encodeSRegister(OpSd, "Sd", Vabss);
2334 IValueT Sm = encodeSRegister(OpSm, "Sm", Vabss);
2335 constexpr IValueT S0 = 0;
2336 constexpr IValueT VabssOpcode = B23 | B21 | B20 | B7 | B6;
2337 emitVFPsss(Cond, VabssOpcode, Sd, S0, Sm);
2338 }
2339
vabsd(const Operand * OpDd,const Operand * OpDm,CondARM32::Cond Cond)2340 void AssemblerARM32::vabsd(const Operand *OpDd, const Operand *OpDm,
2341 CondARM32::Cond Cond) {
2342 // VABS - ARM section A8.8.280, encoding A2:
2343 // vabs<c>.f64 <Dd>, <Dm>
2344 //
2345 // cccc11101D110000dddd101111M0mmmm where cccc=Cond, Ddddd=Dd, and Mmmmm=Dm.
2346 constexpr const char *Vabsd = "vabsd";
2347 const IValueT Dd = encodeDRegister(OpDd, "Dd", Vabsd);
2348 const IValueT Dm = encodeDRegister(OpDm, "Dm", Vabsd);
2349 constexpr IValueT D0 = 0;
2350 constexpr IValueT VabsdOpcode = B23 | B21 | B20 | B7 | B6;
2351 emitVFPddd(Cond, VabsdOpcode, Dd, D0, Dm);
2352 }
2353
vabsq(const Operand * OpQd,const Operand * OpQm)2354 void AssemblerARM32::vabsq(const Operand *OpQd, const Operand *OpQm) {
2355 // VABS - ARM section A8.8.280, encoding A1:
2356 // vabs.<dt> <Qd>, <Qm>
2357 //
2358 // 111100111D11ss01ddd0f1101M0mmm0 where Dddd=OpQd, Mddd=OpQm, and
2359 // <dt> in {s8, s16, s32, f32} and ss is the encoding of <dt>.
2360 const Type ElmtTy = typeElementType(OpQd->getType());
2361 assert(ElmtTy != IceType_i64 && "vabsq doesn't allow i64!");
2362 constexpr const char *Vabsq = "vabsq";
2363 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vabsq));
2364 const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vabsq));
2365 constexpr IValueT Dn = 0;
2366 const IValueT VabsqOpcode =
2367 B24 | B23 | B21 | B20 | B16 | B9 | B8 | (encodeElmtType(ElmtTy) << 18);
2368 constexpr bool UseQRegs = true;
2369 emitSIMDBase(VabsqOpcode, Dd, Dn, Dm, UseQRegs, isFloatingType(ElmtTy));
2370 }
2371
vadds(const Operand * OpSd,const Operand * OpSn,const Operand * OpSm,CondARM32::Cond Cond)2372 void AssemblerARM32::vadds(const Operand *OpSd, const Operand *OpSn,
2373 const Operand *OpSm, CondARM32::Cond Cond) {
2374 // VADD (floating-point) - ARM section A8.8.283, encoding A2:
2375 // vadd<c>.f32 <Sd>, <Sn>, <Sm>
2376 //
2377 // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn,
2378 // and mmmmM=Rm.
2379 constexpr const char *Vadds = "vadds";
2380 constexpr IValueT VaddsOpcode = B21 | B20;
2381 emitVFPsss(Cond, VaddsOpcode, OpSd, OpSn, OpSm, Vadds);
2382 }
2383
vaddqi(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2384 void AssemblerARM32::vaddqi(Type ElmtTy, const Operand *OpQd,
2385 const Operand *OpQm, const Operand *OpQn) {
2386 // VADD (integer) - ARM section A8.8.282, encoding A1:
2387 // vadd.<dt> <Qd>, <Qn>, <Qm>
2388 //
2389 // 111100100Dssnnn0ddd01000N1M0mmm0 where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm,
2390 // and dt in [i8, i16, i32, i64] where ss is the index.
2391 assert(isScalarIntegerType(ElmtTy) &&
2392 "vaddqi expects vector with integer element type");
2393 constexpr const char *Vaddqi = "vaddqi";
2394 constexpr IValueT VaddqiOpcode = B11;
2395 emitSIMDqqq(VaddqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vaddqi);
2396 }
2397
vaddqf(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)2398 void AssemblerARM32::vaddqf(const Operand *OpQd, const Operand *OpQn,
2399 const Operand *OpQm) {
2400 // VADD (floating-point) - ARM section A8.8.283, Encoding A1:
2401 // vadd.f32 <Qd>, <Qn>, <Qm>
2402 //
2403 // 111100100D00nnn0ddd01101N1M0mmm0 where Dddd=Qd, Nnnn=Qn, and Mmmm=Qm.
2404 assert(OpQd->getType() == IceType_v4f32 && "vaddqf expects type <4 x float>");
2405 constexpr const char *Vaddqf = "vaddqf";
2406 constexpr IValueT VaddqfOpcode = B11 | B8;
2407 constexpr bool IsFloatTy = true;
2408 emitSIMDqqqBase(VaddqfOpcode, OpQd, OpQn, OpQm, IsFloatTy, Vaddqf);
2409 }
2410
vaddd(const Operand * OpDd,const Operand * OpDn,const Operand * OpDm,CondARM32::Cond Cond)2411 void AssemblerARM32::vaddd(const Operand *OpDd, const Operand *OpDn,
2412 const Operand *OpDm, CondARM32::Cond Cond) {
2413 // VADD (floating-point) - ARM section A8.8.283, encoding A2:
2414 // vadd<c>.f64 <Dd>, <Dn>, <Dm>
2415 //
2416 // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn,
2417 // and Mmmmm=Rm.
2418 constexpr const char *Vaddd = "vaddd";
2419 constexpr IValueT VadddOpcode = B21 | B20;
2420 emitVFPddd(Cond, VadddOpcode, OpDd, OpDn, OpDm, Vaddd);
2421 }
2422
vandq(const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2423 void AssemblerARM32::vandq(const Operand *OpQd, const Operand *OpQm,
2424 const Operand *OpQn) {
2425 // VAND (register) - ARM section A8.8.287, encoding A1:
2426 // vand <Qd>, <Qn>, <Qm>
2427 //
2428 // 111100100D00nnn0ddd00001N1M1mmm0 where Dddd=OpQd, Nnnn=OpQm, and Mmmm=OpQm.
2429 constexpr const char *Vandq = "vandq";
2430 constexpr IValueT VandqOpcode = B8 | B4;
2431 constexpr Type ElmtTy = IceType_i8;
2432 emitSIMDqqq(VandqOpcode, ElmtTy, OpQd, OpQm, OpQn, Vandq);
2433 }
2434
vbslq(const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2435 void AssemblerARM32::vbslq(const Operand *OpQd, const Operand *OpQm,
2436 const Operand *OpQn) {
2437 // VBSL (register) - ARM section A8.8.290, encoding A1:
2438 // vbsl <Qd>, <Qn>, <Qm>
2439 //
2440 // 111100110D01nnn0ddd00001N1M1mmm0 where Dddd=OpQd, Nnnn=OpQm, and Mmmm=OpQm.
2441 constexpr const char *Vbslq = "vbslq";
2442 constexpr IValueT VbslqOpcode = B24 | B20 | B8 | B4;
2443 constexpr Type ElmtTy = IceType_i8; // emits sz=0
2444 emitSIMDqqq(VbslqOpcode, ElmtTy, OpQd, OpQm, OpQn, Vbslq);
2445 }
2446
vceqqi(const Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2447 void AssemblerARM32::vceqqi(const Type ElmtTy, const Operand *OpQd,
2448 const Operand *OpQm, const Operand *OpQn) {
2449 // vceq (register) - ARM section A8.8.291, encoding A1:
2450 // vceq.<st> <Qd>, <Qn>, <Qm>
2451 //
2452 // 111100110Dssnnnndddd1000NQM1mmmm where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm, and
2453 // st in [i8, i16, i32] where ss is the index.
2454 constexpr const char *Vceq = "vceq";
2455 constexpr IValueT VceqOpcode = B24 | B11 | B4;
2456 emitSIMDqqq(VceqOpcode, ElmtTy, OpQd, OpQm, OpQn, Vceq);
2457 }
2458
vceqqs(const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2459 void AssemblerARM32::vceqqs(const Operand *OpQd, const Operand *OpQm,
2460 const Operand *OpQn) {
2461 // vceq (register) - ARM section A8.8.291, encoding A2:
2462 // vceq.f32 <Qd>, <Qn>, <Qm>
2463 //
2464 // 111100100D00nnnndddd1110NQM0mmmm where Dddd=OpQd, Nnnn=OpQm, and Mmmm=OpQm.
2465 constexpr const char *Vceq = "vceq";
2466 constexpr IValueT VceqOpcode = B11 | B10 | B9;
2467 constexpr Type ElmtTy = IceType_i8; // encoded as 0b00
2468 emitSIMDqqq(VceqOpcode, ElmtTy, OpQd, OpQm, OpQn, Vceq);
2469 }
2470
vcgeqi(const Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2471 void AssemblerARM32::vcgeqi(const Type ElmtTy, const Operand *OpQd,
2472 const Operand *OpQm, const Operand *OpQn) {
2473 // vcge (register) - ARM section A8.8.293, encoding A1:
2474 // vcge.<st> <Qd>, <Qn>, <Qm>
2475 //
2476 // 1111001U0Dssnnnndddd0011NQM1mmmm where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm,
2477 // 0=U, and st in [s8, s16, s32] where ss is the index.
2478 constexpr const char *Vcge = "vcge";
2479 constexpr IValueT VcgeOpcode = B9 | B8 | B4;
2480 emitSIMDqqq(VcgeOpcode, ElmtTy, OpQd, OpQm, OpQn, Vcge);
2481 }
2482
vcugeqi(const Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2483 void AssemblerARM32::vcugeqi(const Type ElmtTy, const Operand *OpQd,
2484 const Operand *OpQm, const Operand *OpQn) {
2485 // vcge (register) - ARM section A8.8.293, encoding A1:
2486 // vcge.<st> <Qd>, <Qn>, <Qm>
2487 //
2488 // 1111001U0Dssnnnndddd0011NQM1mmmm where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm,
2489 // 1=U, and st in [u8, u16, u32] where ss is the index.
2490 constexpr const char *Vcge = "vcge";
2491 constexpr IValueT VcgeOpcode = B24 | B9 | B8 | B4;
2492 emitSIMDqqq(VcgeOpcode, ElmtTy, OpQd, OpQm, OpQn, Vcge);
2493 }
2494
vcgeqs(const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2495 void AssemblerARM32::vcgeqs(const Operand *OpQd, const Operand *OpQm,
2496 const Operand *OpQn) {
2497 // vcge (register) - ARM section A8.8.293, encoding A2:
2498 // vcge.f32 <Qd>, <Qn>, <Qm>
2499 //
2500 // 111100110D00nnnndddd1110NQM0mmmm where Dddd=OpQd, Nnnn=OpQm, and Mmmm=OpQm.
2501 constexpr const char *Vcge = "vcge";
2502 constexpr IValueT VcgeOpcode = B24 | B11 | B10 | B9;
2503 constexpr Type ElmtTy = IceType_i8; // encoded as 0b00.
2504 emitSIMDqqq(VcgeOpcode, ElmtTy, OpQd, OpQm, OpQn, Vcge);
2505 }
2506
vcgtqi(const Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2507 void AssemblerARM32::vcgtqi(const Type ElmtTy, const Operand *OpQd,
2508 const Operand *OpQm, const Operand *OpQn) {
2509 // vcgt (register) - ARM section A8.8.295, encoding A1:
2510 // vcgt.<st> <Qd>, <Qn>, <Qm>
2511 //
2512 // 1111001U0Dssnnnndddd0011NQM0mmmm where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm,
2513 // 0=U, and st in [s8, s16, s32] where ss is the index.
2514 constexpr const char *Vcge = "vcgt";
2515 constexpr IValueT VcgeOpcode = B9 | B8;
2516 emitSIMDqqq(VcgeOpcode, ElmtTy, OpQd, OpQm, OpQn, Vcge);
2517 }
2518
vcugtqi(const Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2519 void AssemblerARM32::vcugtqi(const Type ElmtTy, const Operand *OpQd,
2520 const Operand *OpQm, const Operand *OpQn) {
2521 // vcgt (register) - ARM section A8.8.295, encoding A1:
2522 // vcgt.<st> <Qd>, <Qn>, <Qm>
2523 //
2524 // 111100110Dssnnnndddd0011NQM0mmmm where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm,
2525 // 1=U, and st in [u8, u16, u32] where ss is the index.
2526 constexpr const char *Vcge = "vcgt";
2527 constexpr IValueT VcgeOpcode = B24 | B9 | B8;
2528 emitSIMDqqq(VcgeOpcode, ElmtTy, OpQd, OpQm, OpQn, Vcge);
2529 }
2530
vcgtqs(const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)2531 void AssemblerARM32::vcgtqs(const Operand *OpQd, const Operand *OpQm,
2532 const Operand *OpQn) {
2533 // vcgt (register) - ARM section A8.8.295, encoding A2:
2534 // vcgt.f32 <Qd>, <Qn>, <Qm>
2535 //
2536 // 111100110D10nnnndddd1110NQM0mmmm where Dddd=OpQd, Nnnn=OpQm, and Mmmm=OpQm.
2537 constexpr const char *Vcge = "vcgt";
2538 constexpr IValueT VcgeOpcode = B24 | B21 | B11 | B10 | B9;
2539 constexpr Type ElmtTy = IceType_i8; // encoded as 0b00.
2540 emitSIMDqqq(VcgeOpcode, ElmtTy, OpQd, OpQm, OpQn, Vcge);
2541 }
2542
vcmpd(const Operand * OpDd,const Operand * OpDm,CondARM32::Cond Cond)2543 void AssemblerARM32::vcmpd(const Operand *OpDd, const Operand *OpDm,
2544 CondARM32::Cond Cond) {
2545 constexpr const char *Vcmpd = "vcmpd";
2546 IValueT Dd = encodeDRegister(OpDd, "Dd", Vcmpd);
2547 IValueT Dm = encodeDRegister(OpDm, "Dm", Vcmpd);
2548 constexpr IValueT VcmpdOpcode = B23 | B21 | B20 | B18 | B6;
2549 constexpr IValueT Dn = 0;
2550 emitVFPddd(Cond, VcmpdOpcode, Dd, Dn, Dm);
2551 }
2552
vcmpdz(const Operand * OpDd,CondARM32::Cond Cond)2553 void AssemblerARM32::vcmpdz(const Operand *OpDd, CondARM32::Cond Cond) {
2554 constexpr const char *Vcmpdz = "vcmpdz";
2555 IValueT Dd = encodeDRegister(OpDd, "Dd", Vcmpdz);
2556 constexpr IValueT VcmpdzOpcode = B23 | B21 | B20 | B18 | B16 | B6;
2557 constexpr IValueT Dn = 0;
2558 constexpr IValueT Dm = 0;
2559 emitVFPddd(Cond, VcmpdzOpcode, Dd, Dn, Dm);
2560 }
2561
vcmps(const Operand * OpSd,const Operand * OpSm,CondARM32::Cond Cond)2562 void AssemblerARM32::vcmps(const Operand *OpSd, const Operand *OpSm,
2563 CondARM32::Cond Cond) {
2564 constexpr const char *Vcmps = "vcmps";
2565 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcmps);
2566 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcmps);
2567 constexpr IValueT VcmpsOpcode = B23 | B21 | B20 | B18 | B6;
2568 constexpr IValueT Sn = 0;
2569 emitVFPsss(Cond, VcmpsOpcode, Sd, Sn, Sm);
2570 }
2571
vcmpsz(const Operand * OpSd,CondARM32::Cond Cond)2572 void AssemblerARM32::vcmpsz(const Operand *OpSd, CondARM32::Cond Cond) {
2573 constexpr const char *Vcmpsz = "vcmps";
2574 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcmpsz);
2575 constexpr IValueT VcmpszOpcode = B23 | B21 | B20 | B18 | B16 | B6;
2576 constexpr IValueT Sn = 0;
2577 constexpr IValueT Sm = 0;
2578 emitVFPsss(Cond, VcmpszOpcode, Sd, Sn, Sm);
2579 }
2580
emitVFPsd(CondARM32::Cond Cond,IValueT Opcode,IValueT Sd,IValueT Dm)2581 void AssemblerARM32::emitVFPsd(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd,
2582 IValueT Dm) {
2583 assert(Sd < RegARM32::getNumSRegs());
2584 assert(Dm < RegARM32::getNumDRegs());
2585 assert(CondARM32::isDefined(Cond));
2586 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9;
2587 const IValueT Encoding =
2588 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
2589 (getYInRegXXXXY(Sd) << 22) | (getXXXXInRegXXXXY(Sd) << 12) |
2590 (getYInRegYXXXX(Dm) << 5) | getXXXXInRegYXXXX(Dm);
2591 emitInst(Encoding);
2592 }
2593
vcvtdi(const Operand * OpDd,const Operand * OpSm,CondARM32::Cond Cond)2594 void AssemblerARM32::vcvtdi(const Operand *OpDd, const Operand *OpSm,
2595 CondARM32::Cond Cond) {
2596 // VCVT (between floating-point and integer, Floating-point)
2597 // - ARM Section A8.8.306, encoding A1:
2598 // vcvt<c>.f64.s32 <Dd>, <Sm>
2599 //
2600 // cccc11101D111000dddd10111M0mmmm where cccc=Cond, Ddddd=Dd, and mmmmM=Sm.
2601 constexpr const char *Vcvtdi = "vcvtdi";
2602 IValueT Dd = encodeDRegister(OpDd, "Dd", Vcvtdi);
2603 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtdi);
2604 constexpr IValueT VcvtdiOpcode = B23 | B21 | B20 | B19 | B8 | B7 | B6;
2605 emitVFPds(Cond, VcvtdiOpcode, Dd, Sm);
2606 }
2607
vcvtdu(const Operand * OpDd,const Operand * OpSm,CondARM32::Cond Cond)2608 void AssemblerARM32::vcvtdu(const Operand *OpDd, const Operand *OpSm,
2609 CondARM32::Cond Cond) {
2610 // VCVT (between floating-point and integer, Floating-point)
2611 // - ARM Section A8.8.306, encoding A1:
2612 // vcvt<c>.f64.u32 <Dd>, <Sm>
2613 //
2614 // cccc11101D111000dddd10101M0mmmm where cccc=Cond, Ddddd=Dd, and mmmmM=Sm.
2615 constexpr const char *Vcvtdu = "vcvtdu";
2616 IValueT Dd = encodeDRegister(OpDd, "Dd", Vcvtdu);
2617 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtdu);
2618 constexpr IValueT VcvtduOpcode = B23 | B21 | B20 | B19 | B8 | B6;
2619 emitVFPds(Cond, VcvtduOpcode, Dd, Sm);
2620 }
2621
vcvtsd(const Operand * OpSd,const Operand * OpDm,CondARM32::Cond Cond)2622 void AssemblerARM32::vcvtsd(const Operand *OpSd, const Operand *OpDm,
2623 CondARM32::Cond Cond) {
2624 constexpr const char *Vcvtsd = "vcvtsd";
2625 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtsd);
2626 IValueT Dm = encodeDRegister(OpDm, "Dm", Vcvtsd);
2627 constexpr IValueT VcvtsdOpcode =
2628 B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6;
2629 emitVFPsd(Cond, VcvtsdOpcode, Sd, Dm);
2630 }
2631
vcvtis(const Operand * OpSd,const Operand * OpSm,CondARM32::Cond Cond)2632 void AssemblerARM32::vcvtis(const Operand *OpSd, const Operand *OpSm,
2633 CondARM32::Cond Cond) {
2634 // VCVT (between floating-point and integer, Floating-point)
2635 // - ARM Section A8.8.306, encoding A1:
2636 // vcvt<c>.s32.f32 <Sd>, <Sm>
2637 //
2638 // cccc11101D111101dddd10011M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
2639 constexpr const char *Vcvtis = "vcvtis";
2640 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtis);
2641 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtis);
2642 constexpr IValueT VcvtisOpcode = B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6;
2643 constexpr IValueT S0 = 0;
2644 emitVFPsss(Cond, VcvtisOpcode, Sd, S0, Sm);
2645 }
2646
vcvtid(const Operand * OpSd,const Operand * OpDm,CondARM32::Cond Cond)2647 void AssemblerARM32::vcvtid(const Operand *OpSd, const Operand *OpDm,
2648 CondARM32::Cond Cond) {
2649 // VCVT (between floating-point and integer, Floating-point)
2650 // - ARM Section A8.8.306, encoding A1:
2651 // vcvt<c>.s32.f64 <Sd>, <Dm>
2652 //
2653 // cccc11101D111101dddd10111M0mmmm where cccc=Cond, ddddD=Sd, and Mmmmm=Dm.
2654 constexpr const char *Vcvtid = "vcvtid";
2655 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtid);
2656 IValueT Dm = encodeDRegister(OpDm, "Dm", Vcvtid);
2657 constexpr IValueT VcvtidOpcode =
2658 B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6;
2659 emitVFPsd(Cond, VcvtidOpcode, Sd, Dm);
2660 }
2661
vcvtsi(const Operand * OpSd,const Operand * OpSm,CondARM32::Cond Cond)2662 void AssemblerARM32::vcvtsi(const Operand *OpSd, const Operand *OpSm,
2663 CondARM32::Cond Cond) {
2664 // VCVT (between floating-point and integer, Floating-point)
2665 // - ARM Section A8.8.306, encoding A1:
2666 // vcvt<c>.f32.s32 <Sd>, <Sm>
2667 //
2668 // cccc11101D111000dddd10011M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
2669 constexpr const char *Vcvtsi = "vcvtsi";
2670 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtsi);
2671 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtsi);
2672 constexpr IValueT VcvtsiOpcode = B23 | B21 | B20 | B19 | B7 | B6;
2673 constexpr IValueT S0 = 0;
2674 emitVFPsss(Cond, VcvtsiOpcode, Sd, S0, Sm);
2675 }
2676
vcvtsu(const Operand * OpSd,const Operand * OpSm,CondARM32::Cond Cond)2677 void AssemblerARM32::vcvtsu(const Operand *OpSd, const Operand *OpSm,
2678 CondARM32::Cond Cond) {
2679 // VCVT (between floating-point and integer, Floating-point)
2680 // - ARM Section A8.8.306, encoding A1:
2681 // vcvt<c>.f32.u32 <Sd>, <Sm>
2682 //
2683 // cccc11101D111000dddd10001M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
2684 constexpr const char *Vcvtsu = "vcvtsu";
2685 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtsu);
2686 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtsu);
2687 constexpr IValueT VcvtsuOpcode = B23 | B21 | B20 | B19 | B6;
2688 constexpr IValueT S0 = 0;
2689 emitVFPsss(Cond, VcvtsuOpcode, Sd, S0, Sm);
2690 }
2691
vcvtud(const Operand * OpSd,const Operand * OpDm,CondARM32::Cond Cond)2692 void AssemblerARM32::vcvtud(const Operand *OpSd, const Operand *OpDm,
2693 CondARM32::Cond Cond) {
2694 // VCVT (between floating-point and integer, Floating-point)
2695 // - ARM Section A8.8.306, encoding A1:
2696 // vcvt<c>.u32.f64 <Sd>, <Dm>
2697 //
2698 // cccc11101D111100dddd10111M0mmmm where cccc=Cond, ddddD=Sd, and Mmmmm=Dm.
2699 constexpr const char *Vcvtud = "vcvtud";
2700 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtud);
2701 IValueT Dm = encodeDRegister(OpDm, "Dm", Vcvtud);
2702 constexpr IValueT VcvtudOpcode = B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6;
2703 emitVFPsd(Cond, VcvtudOpcode, Sd, Dm);
2704 }
2705
vcvtus(const Operand * OpSd,const Operand * OpSm,CondARM32::Cond Cond)2706 void AssemblerARM32::vcvtus(const Operand *OpSd, const Operand *OpSm,
2707 CondARM32::Cond Cond) {
2708 // VCVT (between floating-point and integer, Floating-point)
2709 // - ARM Section A8.8.306, encoding A1:
2710 // vcvt<c>.u32.f32 <Sd>, <Sm>
2711 //
2712 // cccc11101D111100dddd10011M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
2713 constexpr const char *Vcvtus = "vcvtus";
2714 IValueT Sd = encodeSRegister(OpSd, "Sd", Vcvtus);
2715 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtus);
2716 constexpr IValueT VcvtsiOpcode = B23 | B21 | B20 | B19 | B18 | B7 | B6;
2717 constexpr IValueT S0 = 0;
2718 emitVFPsss(Cond, VcvtsiOpcode, Sd, S0, Sm);
2719 }
2720
vcvtqsi(const Operand * OpQd,const Operand * OpQm)2721 void AssemblerARM32::vcvtqsi(const Operand *OpQd, const Operand *OpQm) {
2722 // VCVT (between floating-point and integer, Advanced SIMD)
2723 // - ARM Section A8.8.305, encoding A1:
2724 // vcvt<c>.f32.s32 <Qd>, <Qm>
2725 //
2726 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 10=op.
2727 constexpr const char *Vcvtqsi = "vcvt.s32.f32";
2728 constexpr IValueT VcvtqsiOpcode = B8;
2729 emitSIMDCvtqq(VcvtqsiOpcode, OpQd, OpQm, Vcvtqsi);
2730 }
2731
vcvtqsu(const Operand * OpQd,const Operand * OpQm)2732 void AssemblerARM32::vcvtqsu(const Operand *OpQd, const Operand *OpQm) {
2733 // VCVT (between floating-point and integer, Advanced SIMD)
2734 // - ARM Section A8.8.305, encoding A1:
2735 // vcvt<c>.f32.u32 <Qd>, <Qm>
2736 //
2737 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 11=op.
2738 constexpr const char *Vcvtqsu = "vcvt.u32.f32";
2739 constexpr IValueT VcvtqsuOpcode = B8 | B7;
2740 emitSIMDCvtqq(VcvtqsuOpcode, OpQd, OpQm, Vcvtqsu);
2741 }
2742
vcvtqis(const Operand * OpQd,const Operand * OpQm)2743 void AssemblerARM32::vcvtqis(const Operand *OpQd, const Operand *OpQm) {
2744 // VCVT (between floating-point and integer, Advanced SIMD)
2745 // - ARM Section A8.8.305, encoding A1:
2746 // vcvt<c>.f32.s32 <Qd>, <Qm>
2747 //
2748 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 01=op.
2749 constexpr const char *Vcvtqis = "vcvt.f32.s32";
2750 constexpr IValueT VcvtqisOpcode = 0;
2751 emitSIMDCvtqq(VcvtqisOpcode, OpQd, OpQm, Vcvtqis);
2752 }
2753
vcvtqus(const Operand * OpQd,const Operand * OpQm)2754 void AssemblerARM32::vcvtqus(const Operand *OpQd, const Operand *OpQm) {
2755 // VCVT (between floating-point and integer, Advanced SIMD)
2756 // - ARM Section A8.8.305, encoding A1:
2757 // vcvt<c>.f32.u32 <Qd>, <Qm>
2758 //
2759 // 111100111D11ss11dddd011ooQM0mmmm where Ddddd=Qd, Mmmmm=Qm, and 01=op.
2760 constexpr const char *Vcvtqus = "vcvt.f32.u32";
2761 constexpr IValueT VcvtqusOpcode = B7;
2762 emitSIMDCvtqq(VcvtqusOpcode, OpQd, OpQm, Vcvtqus);
2763 }
2764
emitVFPds(CondARM32::Cond Cond,IValueT Opcode,IValueT Dd,IValueT Sm)2765 void AssemblerARM32::emitVFPds(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd,
2766 IValueT Sm) {
2767 assert(Dd < RegARM32::getNumDRegs());
2768 assert(Sm < RegARM32::getNumSRegs());
2769 assert(CondARM32::isDefined(Cond));
2770 constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9;
2771 const IValueT Encoding =
2772 Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
2773 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dd) << 12) |
2774 (getYInRegXXXXY(Sm) << 5) | getXXXXInRegXXXXY(Sm);
2775 emitInst(Encoding);
2776 }
2777
vcvtds(const Operand * OpDd,const Operand * OpSm,CondARM32::Cond Cond)2778 void AssemblerARM32::vcvtds(const Operand *OpDd, const Operand *OpSm,
2779 CondARM32::Cond Cond) {
2780 constexpr const char *Vcvtds = "Vctds";
2781 IValueT Dd = encodeDRegister(OpDd, "Dd", Vcvtds);
2782 IValueT Sm = encodeSRegister(OpSm, "Sm", Vcvtds);
2783 constexpr IValueT VcvtdsOpcode = B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6;
2784 emitVFPds(Cond, VcvtdsOpcode, Dd, Sm);
2785 }
2786
vdivs(const Operand * OpSd,const Operand * OpSn,const Operand * OpSm,CondARM32::Cond Cond)2787 void AssemblerARM32::vdivs(const Operand *OpSd, const Operand *OpSn,
2788 const Operand *OpSm, CondARM32::Cond Cond) {
2789 // VDIV (floating-point) - ARM section A8.8.283, encoding A2:
2790 // vdiv<c>.f32 <Sd>, <Sn>, <Sm>
2791 //
2792 // cccc11101D00nnnndddd101sN0M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn,
2793 // and mmmmM=Rm.
2794 constexpr const char *Vdivs = "vdivs";
2795 constexpr IValueT VdivsOpcode = B23;
2796 emitVFPsss(Cond, VdivsOpcode, OpSd, OpSn, OpSm, Vdivs);
2797 }
2798
vdivd(const Operand * OpDd,const Operand * OpDn,const Operand * OpDm,CondARM32::Cond Cond)2799 void AssemblerARM32::vdivd(const Operand *OpDd, const Operand *OpDn,
2800 const Operand *OpDm, CondARM32::Cond Cond) {
2801 // VDIV (floating-point) - ARM section A8.8.283, encoding A2:
2802 // vdiv<c>.f64 <Dd>, <Dn>, <Dm>
2803 //
2804 // cccc11101D00nnnndddd101sN0M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn,
2805 // and Mmmmm=Rm.
2806 constexpr const char *Vdivd = "vdivd";
2807 constexpr IValueT VdivdOpcode = B23;
2808 emitVFPddd(Cond, VdivdOpcode, OpDd, OpDn, OpDm, Vdivd);
2809 }
2810
veord(const Operand * OpDd,const Operand * OpDn,const Operand * OpDm)2811 void AssemblerARM32::veord(const Operand *OpDd, const Operand *OpDn,
2812 const Operand *OpDm) {
2813 // VEOR - ARM secdtion A8.8.315, encoding A1:
2814 // veor<c> <Dd>, <Dn>, <Dm>
2815 //
2816 // 111100110D00nnnndddd0001N0M1mmmm where Ddddd=Dd, Nnnnn=Dn, and Mmmmm=Dm.
2817 constexpr const char *Veord = "veord";
2818 IValueT Dd = encodeDRegister(OpDd, "Dd", Veord);
2819 IValueT Dn = encodeDRegister(OpDn, "Dn", Veord);
2820 IValueT Dm = encodeDRegister(OpDm, "Dm", Veord);
2821 const IValueT Encoding =
2822 B25 | B24 | B8 | B4 |
2823 (encodeCondition(CondARM32::Cond::kNone) << kConditionShift) |
2824 (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) |
2825 (getXXXXInRegYXXXX(Dd) << 12) | (getYInRegYXXXX(Dn) << 7) |
2826 (getYInRegYXXXX(Dm) << 5) | getXXXXInRegYXXXX(Dm);
2827 emitInst(Encoding);
2828 }
2829
veorq(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)2830 void AssemblerARM32::veorq(const Operand *OpQd, const Operand *OpQn,
2831 const Operand *OpQm) {
2832 // VEOR - ARM section A8.8.316, encoding A1:
2833 // veor <Qd>, <Qn>, <Qm>
2834 //
2835 // 111100110D00nnn0ddd00001N1M1mmm0 where Dddd=Qd, Nnnn=Qn, and Mmmm=Qm.
2836 constexpr const char *Veorq = "veorq";
2837 constexpr IValueT VeorqOpcode = B24 | B8 | B4;
2838 emitSIMDqqq(VeorqOpcode, IceType_i8, OpQd, OpQn, OpQm, Veorq);
2839 }
2840
vldrd(const Operand * OpDd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)2841 void AssemblerARM32::vldrd(const Operand *OpDd, const Operand *OpAddress,
2842 CondARM32::Cond Cond, const TargetInfo &TInfo) {
2843 // VLDR - ARM section A8.8.333, encoding A1.
2844 // vldr<c> <Dd>, [<Rn>{, #+/-<imm>}]
2845 //
2846 // cccc1101UD01nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
2847 // iiiiiiii=abs(Imm >> 2), and U=1 if Opcode>=0.
2848 constexpr const char *Vldrd = "vldrd";
2849 IValueT Dd = encodeDRegister(OpDd, "Dd", Vldrd);
2850 assert(CondARM32::isDefined(Cond));
2851 IValueT Address;
2852 EncodedOperand AddressEncoding =
2853 encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
2854 (void)AddressEncoding;
2855 assert(AddressEncoding == EncodedAsImmRegOffset);
2856 IValueT Encoding = B27 | B26 | B24 | B20 | B11 | B9 | B8 |
2857 (encodeCondition(Cond) << kConditionShift) |
2858 (getYInRegYXXXX(Dd) << 22) |
2859 (getXXXXInRegYXXXX(Dd) << 12) | Address;
2860 emitInst(Encoding);
2861 }
2862
vldrq(const Operand * OpQd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)2863 void AssemblerARM32::vldrq(const Operand *OpQd, const Operand *OpAddress,
2864 CondARM32::Cond Cond, const TargetInfo &TInfo) {
2865 // This is a pseudo-instruction which loads 64-bit data into a quadword
2866 // vector register. It is implemented by loading into the lower doubleword.
2867
2868 // VLDR - ARM section A8.8.333, encoding A1.
2869 // vldr<c> <Dd>, [<Rn>{, #+/-<imm>}]
2870 //
2871 // cccc1101UD01nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
2872 // iiiiiiii=abs(Imm >> 2), and U=1 if Opcode>=0.
2873 constexpr const char *Vldrd = "vldrd";
2874 IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vldrd));
2875 assert(CondARM32::isDefined(Cond));
2876 IValueT Address;
2877 EncodedOperand AddressEncoding =
2878 encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
2879 (void)AddressEncoding;
2880 assert(AddressEncoding == EncodedAsImmRegOffset);
2881 IValueT Encoding = B27 | B26 | B24 | B20 | B11 | B9 | B8 |
2882 (encodeCondition(Cond) << kConditionShift) |
2883 (getYInRegYXXXX(Dd) << 22) |
2884 (getXXXXInRegYXXXX(Dd) << 12) | Address;
2885 emitInst(Encoding);
2886 }
2887
vldrs(const Operand * OpSd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)2888 void AssemblerARM32::vldrs(const Operand *OpSd, const Operand *OpAddress,
2889 CondARM32::Cond Cond, const TargetInfo &TInfo) {
2890 // VDLR - ARM section A8.8.333, encoding A2.
2891 // vldr<c> <Sd>, [<Rn>{, #+/-<imm>]]
2892 //
2893 // cccc1101UD01nnnndddd1010iiiiiiii where cccc=Cond, nnnn=Rn, ddddD=Sd,
2894 // iiiiiiii=abs(Opcode), and U=1 if Opcode >= 0;
2895 constexpr const char *Vldrs = "vldrs";
2896 IValueT Sd = encodeSRegister(OpSd, "Sd", Vldrs);
2897 assert(CondARM32::isDefined(Cond));
2898 IValueT Address;
2899 EncodedOperand AddressEncoding =
2900 encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
2901 (void)AddressEncoding;
2902 assert(AddressEncoding == EncodedAsImmRegOffset);
2903 IValueT Encoding = B27 | B26 | B24 | B20 | B11 | B9 |
2904 (encodeCondition(Cond) << kConditionShift) |
2905 (getYInRegXXXXY(Sd) << 22) |
2906 (getXXXXInRegXXXXY(Sd) << 12) | Address;
2907 emitInst(Encoding);
2908 }
2909
emitVMem1Op(IValueT Opcode,IValueT Dd,IValueT Rn,IValueT Rm,DRegListSize NumDRegs,size_t ElmtSize,IValueT Align,const char * InstName)2910 void AssemblerARM32::emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn,
2911 IValueT Rm, DRegListSize NumDRegs,
2912 size_t ElmtSize, IValueT Align,
2913 const char *InstName) {
2914 assert(Utils::IsAbsoluteUint(2, Align));
2915 IValueT EncodedElmtSize;
2916 switch (ElmtSize) {
2917 default: {
2918 std::string Buffer;
2919 llvm::raw_string_ostream StrBuf(Buffer);
2920 StrBuf << InstName << ": found invalid vector element size " << ElmtSize;
2921 llvm::report_fatal_error(StrBuf.str());
2922 }
2923 case 8:
2924 EncodedElmtSize = 0;
2925 break;
2926 case 16:
2927 EncodedElmtSize = 1;
2928 break;
2929 case 32:
2930 EncodedElmtSize = 2;
2931 break;
2932 case 64:
2933 EncodedElmtSize = 3;
2934 }
2935 const IValueT Encoding =
2936 Opcode | (encodeCondition(CondARM32::kNone) << kConditionShift) |
2937 (getYInRegYXXXX(Dd) << 22) | (Rn << kRnShift) |
2938 (getXXXXInRegYXXXX(Dd) << kRdShift) | (NumDRegs << 8) |
2939 (EncodedElmtSize << 6) | (Align << 4) | Rm;
2940 emitInst(Encoding);
2941 }
2942
emitVMem1Op(IValueT Opcode,IValueT Dd,IValueT Rn,IValueT Rm,size_t ElmtSize,IValueT Align,const char * InstName)2943 void AssemblerARM32::emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn,
2944 IValueT Rm, size_t ElmtSize, IValueT Align,
2945 const char *InstName) {
2946 assert(Utils::IsAbsoluteUint(2, Align));
2947 IValueT EncodedElmtSize;
2948 switch (ElmtSize) {
2949 default: {
2950 std::string Buffer;
2951 llvm::raw_string_ostream StrBuf(Buffer);
2952 StrBuf << InstName << ": found invalid vector element size " << ElmtSize;
2953 llvm::report_fatal_error(StrBuf.str());
2954 }
2955 case 8:
2956 EncodedElmtSize = 0;
2957 break;
2958 case 16:
2959 EncodedElmtSize = 1;
2960 break;
2961 case 32:
2962 EncodedElmtSize = 2;
2963 break;
2964 case 64:
2965 EncodedElmtSize = 3;
2966 }
2967 const IValueT Encoding =
2968 Opcode | (encodeCondition(CondARM32::kNone) << kConditionShift) |
2969 (getYInRegYXXXX(Dd) << 22) | (Rn << kRnShift) |
2970 (getXXXXInRegYXXXX(Dd) << kRdShift) | (EncodedElmtSize << 10) |
2971 (Align << 4) | Rm;
2972 emitInst(Encoding);
2973 }
2974
vld1qr(size_t ElmtSize,const Operand * OpQd,const Operand * OpAddress,const TargetInfo & TInfo)2975 void AssemblerARM32::vld1qr(size_t ElmtSize, const Operand *OpQd,
2976 const Operand *OpAddress, const TargetInfo &TInfo) {
2977 // VLD1 (multiple single elements) - ARM section A8.8.320, encoding A1:
2978 // vld1.<size> <Qd>, [<Rn>]
2979 //
2980 // 111101000D10nnnnddd0ttttssaammmm where tttt=DRegListSize2, Dddd=Qd,
2981 // nnnn=Rn, aa=0 (use default alignment), size=ElmtSize, and ss is the
2982 // encoding of ElmtSize.
2983 constexpr const char *Vld1qr = "vld1qr";
2984 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vld1qr);
2985 const IValueT Dd = mapQRegToDReg(Qd);
2986 IValueT Address;
2987 if (encodeAddress(OpAddress, Address, TInfo, NoImmOffsetAddress) !=
2988 EncodedAsImmRegOffset)
2989 llvm::report_fatal_error(std::string(Vld1qr) + ": malform memory address");
2990 const IValueT Rn = mask(Address, kRnShift, 4);
2991 constexpr IValueT Rm = RegARM32::Reg_pc;
2992 constexpr IValueT Opcode = B26 | B21;
2993 constexpr IValueT Align = 0; // use default alignment.
2994 emitVMem1Op(Opcode, Dd, Rn, Rm, DRegListSize2, ElmtSize, Align, Vld1qr);
2995 }
2996
vld1(size_t ElmtSize,const Operand * OpQd,const Operand * OpAddress,const TargetInfo & TInfo)2997 void AssemblerARM32::vld1(size_t ElmtSize, const Operand *OpQd,
2998 const Operand *OpAddress, const TargetInfo &TInfo) {
2999 // This is a pseudo-instruction for loading a single element of a quadword
3000 // vector. For 64-bit the lower doubleword vector is loaded.
3001
3002 if (ElmtSize == 64) {
3003 return vldrq(OpQd, OpAddress, Ice::CondARM32::AL, TInfo);
3004 }
3005
3006 // VLD1 (single elements to one lane) - ARMv7-A/R section A8.6.308, encoding
3007 // A1:
3008 // VLD1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>
3009 //
3010 // 111101001D10nnnnddddss00aaaammmm where tttt=DRegListSize2, Dddd=Qd,
3011 // nnnn=Rn, aa=0 (use default alignment), size=ElmtSize, and ss is the
3012 // encoding of ElmtSize.
3013 constexpr const char *Vld1qr = "vld1qr";
3014 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vld1qr);
3015 const IValueT Dd = mapQRegToDReg(Qd);
3016 IValueT Address;
3017 if (encodeAddress(OpAddress, Address, TInfo, NoImmOffsetAddress) !=
3018 EncodedAsImmRegOffset)
3019 llvm::report_fatal_error(std::string(Vld1qr) + ": malform memory address");
3020 const IValueT Rn = mask(Address, kRnShift, 4);
3021 constexpr IValueT Rm = RegARM32::Reg_pc;
3022 constexpr IValueT Opcode = B26 | B23 | B21;
3023 constexpr IValueT Align = 0; // use default alignment.
3024 emitVMem1Op(Opcode, Dd, Rn, Rm, ElmtSize, Align, Vld1qr);
3025 }
3026
vmovqc(const Operand * OpQd,const ConstantInteger32 * Imm)3027 bool AssemblerARM32::vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm) {
3028 // VMOV (immediate) - ARM section A8.8.320, encoding A1:
3029 // VMOV.<dt> <Qd>, #<Imm>
3030 // 1111001x1D000yyyddddcccc01p1zzzz where Qd=Ddddd, Imm=xyyyzzzz, cmode=cccc,
3031 // and Op=p.
3032 constexpr const char *Vmovc = "vmovc";
3033 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmovc));
3034 IValueT Value = Imm->getValue();
3035 const Type VecTy = OpQd->getType();
3036 if (!isVectorType(VecTy))
3037 return false;
3038
3039 IValueT Op;
3040 IValueT Cmode;
3041 IValueT Imm8;
3042 if (!encodeAdvSIMDExpandImm(Value, typeElementType(VecTy), Op, Cmode, Imm8))
3043 return false;
3044 if (Op == 0 && mask(Cmode, 0, 1) == 1)
3045 return false;
3046 if (Op == 1 && Cmode != 13)
3047 return false;
3048 const IValueT Encoding =
3049 (0xF << kConditionShift) | B25 | B23 | B6 | B4 |
3050 (mask(Imm8, 7, 1) << 24) | (getYInRegYXXXX(Dd) << 22) |
3051 (mask(Imm8, 4, 3) << 16) | (getXXXXInRegYXXXX(Dd) << 12) | (Cmode << 8) |
3052 (Op << 5) | mask(Imm8, 0, 4);
3053 emitInst(Encoding);
3054 return true;
3055 }
3056
vmovd(const Operand * OpDd,const OperandARM32FlexFpImm * OpFpImm,CondARM32::Cond Cond)3057 void AssemblerARM32::vmovd(const Operand *OpDd,
3058 const OperandARM32FlexFpImm *OpFpImm,
3059 CondARM32::Cond Cond) {
3060 // VMOV (immediate) - ARM section A8.8.339, encoding A2:
3061 // vmov<c>.f64 <Dd>, #<imm>
3062 //
3063 // cccc11101D11xxxxdddd10110000yyyy where cccc=Cond, ddddD=Sn, xxxxyyyy=imm.
3064 constexpr const char *Vmovd = "vmovd";
3065 IValueT Dd = encodeSRegister(OpDd, "Dd", Vmovd);
3066 IValueT Imm8 = OpFpImm->getModifiedImm();
3067 assert(Imm8 < (1 << 8));
3068 constexpr IValueT VmovsOpcode = B23 | B21 | B20 | B8;
3069 IValueT OpcodePlusImm8 = VmovsOpcode | ((Imm8 >> 4) << 16) | (Imm8 & 0xf);
3070 constexpr IValueT D0 = 0;
3071 emitVFPddd(Cond, OpcodePlusImm8, Dd, D0, D0);
3072 }
3073
vmovdd(const Operand * OpDd,const Variable * OpDm,CondARM32::Cond Cond)3074 void AssemblerARM32::vmovdd(const Operand *OpDd, const Variable *OpDm,
3075 CondARM32::Cond Cond) {
3076 // VMOV (register) - ARM section A8.8.340, encoding A2:
3077 // vmov<c>.f64 <Dd>, <Sm>
3078 //
3079 // cccc11101D110000dddd101101M0mmmm where cccc=Cond, Ddddd=Sd, and Mmmmm=Sm.
3080 constexpr const char *Vmovdd = "Vmovdd";
3081 IValueT Dd = encodeSRegister(OpDd, "Dd", Vmovdd);
3082 IValueT Dm = encodeSRegister(OpDm, "Dm", Vmovdd);
3083 constexpr IValueT VmovddOpcode = B23 | B21 | B20 | B6;
3084 constexpr IValueT D0 = 0;
3085 emitVFPddd(Cond, VmovddOpcode, Dd, D0, Dm);
3086 }
3087
vmovdrr(const Operand * OpDm,const Operand * OpRt,const Operand * OpRt2,CondARM32::Cond Cond)3088 void AssemblerARM32::vmovdrr(const Operand *OpDm, const Operand *OpRt,
3089 const Operand *OpRt2, CondARM32::Cond Cond) {
3090 // VMOV (between two ARM core registers and a doubleword extension register).
3091 // ARM section A8.8.345, encoding A1:
3092 // vmov<c> <Dm>, <Rt>, <Rt2>
3093 //
3094 // cccc11000100xxxxyyyy101100M1mmmm where cccc=Cond, xxxx=Rt, yyyy=Rt2, and
3095 // Mmmmm=Dm.
3096 constexpr const char *Vmovdrr = "vmovdrr";
3097 IValueT Dm = encodeDRegister(OpDm, "Dm", Vmovdrr);
3098 IValueT Rt = encodeGPRegister(OpRt, "Rt", Vmovdrr);
3099 IValueT Rt2 = encodeGPRegister(OpRt2, "Rt", Vmovdrr);
3100 assert(Rt != RegARM32::Encoded_Reg_sp);
3101 assert(Rt != RegARM32::Encoded_Reg_pc);
3102 assert(Rt2 != RegARM32::Encoded_Reg_sp);
3103 assert(Rt2 != RegARM32::Encoded_Reg_pc);
3104 assert(Rt != Rt2);
3105 assert(CondARM32::isDefined(Cond));
3106 IValueT Encoding = B27 | B26 | B22 | B11 | B9 | B8 | B4 |
3107 (encodeCondition(Cond) << kConditionShift) | (Rt2 << 16) |
3108 (Rt << 12) | (getYInRegYXXXX(Dm) << 5) |
3109 getXXXXInRegYXXXX(Dm);
3110 emitInst(Encoding);
3111 }
3112
vmovqir(const Operand * OpQn,uint32_t Index,const Operand * OpRt,CondARM32::Cond Cond)3113 void AssemblerARM32::vmovqir(const Operand *OpQn, uint32_t Index,
3114 const Operand *OpRt, CondARM32::Cond Cond) {
3115 // VMOV (ARM core register to scalar) - ARM section A8.8.341, encoding A1:
3116 // vmov<c>.<size> <Dn[x]>, <Rt>
3117 constexpr const char *Vmovdr = "vmovdr";
3118 constexpr bool IsExtract = true;
3119 emitInsertExtractInt(Cond, OpQn, Index, OpRt, !IsExtract, Vmovdr);
3120 }
3121
vmovqis(const Operand * OpQd,uint32_t Index,const Operand * OpSm,CondARM32::Cond Cond)3122 void AssemblerARM32::vmovqis(const Operand *OpQd, uint32_t Index,
3123 const Operand *OpSm, CondARM32::Cond Cond) {
3124 constexpr const char *Vmovqis = "vmovqis";
3125 assert(Index < 4);
3126 IValueT Sd = mapQRegToSReg(encodeQRegister(OpQd, "Qd", Vmovqis)) + Index;
3127 IValueT Sm = encodeSRegister(OpSm, "Sm", Vmovqis);
3128 emitMoveSS(Cond, Sd, Sm);
3129 }
3130
vmovrqi(const Operand * OpRt,const Operand * OpQn,uint32_t Index,CondARM32::Cond Cond)3131 void AssemblerARM32::vmovrqi(const Operand *OpRt, const Operand *OpQn,
3132 uint32_t Index, CondARM32::Cond Cond) {
3133 // VMOV (scalar to ARM core register) - ARM section A8.8.342, encoding A1:
3134 // vmov<c>.<dt> <Rt>, <Dn[x]>
3135 constexpr const char *Vmovrd = "vmovrd";
3136 constexpr bool IsExtract = true;
3137 emitInsertExtractInt(Cond, OpQn, Index, OpRt, IsExtract, Vmovrd);
3138 }
3139
vmovrrd(const Operand * OpRt,const Operand * OpRt2,const Operand * OpDm,CondARM32::Cond Cond)3140 void AssemblerARM32::vmovrrd(const Operand *OpRt, const Operand *OpRt2,
3141 const Operand *OpDm, CondARM32::Cond Cond) {
3142 // VMOV (between two ARM core registers and a doubleword extension register).
3143 // ARM section A8.8.345, encoding A1:
3144 // vmov<c> <Rt>, <Rt2>, <Dm>
3145 //
3146 // cccc11000101xxxxyyyy101100M1mmmm where cccc=Cond, xxxx=Rt, yyyy=Rt2, and
3147 // Mmmmm=Dm.
3148 constexpr const char *Vmovrrd = "vmovrrd";
3149 IValueT Rt = encodeGPRegister(OpRt, "Rt", Vmovrrd);
3150 IValueT Rt2 = encodeGPRegister(OpRt2, "Rt", Vmovrrd);
3151 IValueT Dm = encodeDRegister(OpDm, "Dm", Vmovrrd);
3152 assert(Rt != RegARM32::Encoded_Reg_sp);
3153 assert(Rt != RegARM32::Encoded_Reg_pc);
3154 assert(Rt2 != RegARM32::Encoded_Reg_sp);
3155 assert(Rt2 != RegARM32::Encoded_Reg_pc);
3156 assert(Rt != Rt2);
3157 assert(CondARM32::isDefined(Cond));
3158 IValueT Encoding = B27 | B26 | B22 | B20 | B11 | B9 | B8 | B4 |
3159 (encodeCondition(Cond) << kConditionShift) | (Rt2 << 16) |
3160 (Rt << 12) | (getYInRegYXXXX(Dm) << 5) |
3161 getXXXXInRegYXXXX(Dm);
3162 emitInst(Encoding);
3163 }
3164
vmovrs(const Operand * OpRt,const Operand * OpSn,CondARM32::Cond Cond)3165 void AssemblerARM32::vmovrs(const Operand *OpRt, const Operand *OpSn,
3166 CondARM32::Cond Cond) {
3167 // VMOV (between ARM core register and single-precision register)
3168 // ARM section A8.8.343, encoding A1.
3169 //
3170 // vmov<c> <Rt>, <Sn>
3171 //
3172 // cccc11100001nnnntttt1010N0010000 where cccc=Cond, nnnnN = Sn, and tttt=Rt.
3173 constexpr const char *Vmovrs = "vmovrs";
3174 IValueT Rt = encodeGPRegister(OpRt, "Rt", Vmovrs);
3175 IValueT Sn = encodeSRegister(OpSn, "Sn", Vmovrs);
3176 assert(CondARM32::isDefined(Cond));
3177 IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 | B26 |
3178 B25 | B20 | B11 | B9 | B4 | (getXXXXInRegXXXXY(Sn) << 16) |
3179 (Rt << kRdShift) | (getYInRegXXXXY(Sn) << 7);
3180 emitInst(Encoding);
3181 }
3182
vmovs(const Operand * OpSd,const OperandARM32FlexFpImm * OpFpImm,CondARM32::Cond Cond)3183 void AssemblerARM32::vmovs(const Operand *OpSd,
3184 const OperandARM32FlexFpImm *OpFpImm,
3185 CondARM32::Cond Cond) {
3186 // VMOV (immediate) - ARM section A8.8.339, encoding A2:
3187 // vmov<c>.f32 <Sd>, #<imm>
3188 //
3189 // cccc11101D11xxxxdddd10100000yyyy where cccc=Cond, ddddD=Sn, xxxxyyyy=imm.
3190 constexpr const char *Vmovs = "vmovs";
3191 IValueT Sd = encodeSRegister(OpSd, "Sd", Vmovs);
3192 IValueT Imm8 = OpFpImm->getModifiedImm();
3193 assert(Imm8 < (1 << 8));
3194 constexpr IValueT VmovsOpcode = B23 | B21 | B20;
3195 IValueT OpcodePlusImm8 = VmovsOpcode | ((Imm8 >> 4) << 16) | (Imm8 & 0xf);
3196 constexpr IValueT S0 = 0;
3197 emitVFPsss(Cond, OpcodePlusImm8, Sd, S0, S0);
3198 }
3199
vmovss(const Operand * OpSd,const Variable * OpSm,CondARM32::Cond Cond)3200 void AssemblerARM32::vmovss(const Operand *OpSd, const Variable *OpSm,
3201 CondARM32::Cond Cond) {
3202 constexpr const char *Vmovss = "Vmovss";
3203 IValueT Sd = encodeSRegister(OpSd, "Sd", Vmovss);
3204 IValueT Sm = encodeSRegister(OpSm, "Sm", Vmovss);
3205 emitMoveSS(Cond, Sd, Sm);
3206 }
3207
vmovsqi(const Operand * OpSd,const Operand * OpQm,uint32_t Index,CondARM32::Cond Cond)3208 void AssemblerARM32::vmovsqi(const Operand *OpSd, const Operand *OpQm,
3209 uint32_t Index, CondARM32::Cond Cond) {
3210 constexpr const char *Vmovsqi = "vmovsqi";
3211 const IValueT Sd = encodeSRegister(OpSd, "Sd", Vmovsqi);
3212 assert(Index < 4);
3213 const IValueT Sm =
3214 mapQRegToSReg(encodeQRegister(OpQm, "Qm", Vmovsqi)) + Index;
3215 emitMoveSS(Cond, Sd, Sm);
3216 }
3217
vmovsr(const Operand * OpSn,const Operand * OpRt,CondARM32::Cond Cond)3218 void AssemblerARM32::vmovsr(const Operand *OpSn, const Operand *OpRt,
3219 CondARM32::Cond Cond) {
3220 // VMOV (between ARM core register and single-precision register)
3221 // ARM section A8.8.343, encoding A1.
3222 //
3223 // vmov<c> <Sn>, <Rt>
3224 //
3225 // cccc11100000nnnntttt1010N0010000 where cccc=Cond, nnnnN = Sn, and tttt=Rt.
3226 constexpr const char *Vmovsr = "vmovsr";
3227 IValueT Sn = encodeSRegister(OpSn, "Sn", Vmovsr);
3228 IValueT Rt = encodeGPRegister(OpRt, "Rt", Vmovsr);
3229 assert(Sn < RegARM32::getNumSRegs());
3230 assert(Rt < RegARM32::getNumGPRegs());
3231 assert(CondARM32::isDefined(Cond));
3232 IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 | B26 |
3233 B25 | B11 | B9 | B4 | (getXXXXInRegXXXXY(Sn) << 16) |
3234 (Rt << kRdShift) | (getYInRegXXXXY(Sn) << 7);
3235 emitInst(Encoding);
3236 }
3237
vmlad(const Operand * OpDd,const Operand * OpDn,const Operand * OpDm,CondARM32::Cond Cond)3238 void AssemblerARM32::vmlad(const Operand *OpDd, const Operand *OpDn,
3239 const Operand *OpDm, CondARM32::Cond Cond) {
3240 // VMLA, VMLS (floating-point), ARM section A8.8.337, encoding A2:
3241 // vmla<c>.f64 <Dd>, <Dn>, <Dm>
3242 //
3243 // cccc11100d00nnnndddd1011n0M0mmmm where cccc=Cond, Ddddd=Dd, Nnnnn=Dn, and
3244 // Mmmmm=Dm
3245 constexpr const char *Vmlad = "vmlad";
3246 constexpr IValueT VmladOpcode = 0;
3247 emitVFPddd(Cond, VmladOpcode, OpDd, OpDn, OpDm, Vmlad);
3248 }
3249
vmlas(const Operand * OpSd,const Operand * OpSn,const Operand * OpSm,CondARM32::Cond Cond)3250 void AssemblerARM32::vmlas(const Operand *OpSd, const Operand *OpSn,
3251 const Operand *OpSm, CondARM32::Cond Cond) {
3252 // VMLA, VMLS (floating-point), ARM section A8.8.337, encoding A2:
3253 // vmla<c>.f32 <Sd>, <Sn>, <Sm>
3254 //
3255 // cccc11100d00nnnndddd1010n0M0mmmm where cccc=Cond, ddddD=Sd, nnnnN=Sn, and
3256 // mmmmM=Sm
3257 constexpr const char *Vmlas = "vmlas";
3258 constexpr IValueT VmlasOpcode = 0;
3259 emitVFPsss(Cond, VmlasOpcode, OpSd, OpSn, OpSm, Vmlas);
3260 }
3261
vmlsd(const Operand * OpDd,const Operand * OpDn,const Operand * OpDm,CondARM32::Cond Cond)3262 void AssemblerARM32::vmlsd(const Operand *OpDd, const Operand *OpDn,
3263 const Operand *OpDm, CondARM32::Cond Cond) {
3264 // VMLA, VMLS (floating-point), ARM section A8.8.337, encoding A2:
3265 // vmls<c>.f64 <Dd>, <Dn>, <Dm>
3266 //
3267 // cccc11100d00nnnndddd1011n1M0mmmm where cccc=Cond, Ddddd=Dd, Nnnnn=Dn, and
3268 // Mmmmm=Dm
3269 constexpr const char *Vmlad = "vmlad";
3270 constexpr IValueT VmladOpcode = B6;
3271 emitVFPddd(Cond, VmladOpcode, OpDd, OpDn, OpDm, Vmlad);
3272 }
3273
vmlss(const Operand * OpSd,const Operand * OpSn,const Operand * OpSm,CondARM32::Cond Cond)3274 void AssemblerARM32::vmlss(const Operand *OpSd, const Operand *OpSn,
3275 const Operand *OpSm, CondARM32::Cond Cond) {
3276 // VMLA, VMLS (floating-point), ARM section A8.8.337, encoding A2:
3277 // vmls<c>.f32 <Sd>, <Sn>, <Sm>
3278 //
3279 // cccc11100d00nnnndddd1010n1M0mmmm where cccc=Cond, ddddD=Sd, nnnnN=Sn, and
3280 // mmmmM=Sm
3281 constexpr const char *Vmlas = "vmlas";
3282 constexpr IValueT VmlasOpcode = B6;
3283 emitVFPsss(Cond, VmlasOpcode, OpSd, OpSn, OpSm, Vmlas);
3284 }
3285
vmrsAPSR_nzcv(CondARM32::Cond Cond)3286 void AssemblerARM32::vmrsAPSR_nzcv(CondARM32::Cond Cond) {
3287 // MVRS - ARM section A*.8.348, encoding A1:
3288 // vmrs<c> APSR_nzcv, FPSCR
3289 //
3290 // cccc111011110001tttt101000010000 where tttt=0x15 (i.e. when Rt=pc, use
3291 // APSR_nzcv instead).
3292 assert(CondARM32::isDefined(Cond));
3293 IValueT Encoding = B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 | B15 | B14 |
3294 B13 | B12 | B11 | B9 | B4 |
3295 (encodeCondition(Cond) << kConditionShift);
3296 emitInst(Encoding);
3297 }
3298
vmuls(const Operand * OpSd,const Operand * OpSn,const Operand * OpSm,CondARM32::Cond Cond)3299 void AssemblerARM32::vmuls(const Operand *OpSd, const Operand *OpSn,
3300 const Operand *OpSm, CondARM32::Cond Cond) {
3301 // VMUL (floating-point) - ARM section A8.8.351, encoding A2:
3302 // vmul<c>.f32 <Sd>, <Sn>, <Sm>
3303 //
3304 // cccc11100D10nnnndddd101sN0M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn,
3305 // and mmmmM=Rm.
3306 constexpr const char *Vmuls = "vmuls";
3307 constexpr IValueT VmulsOpcode = B21;
3308 emitVFPsss(Cond, VmulsOpcode, OpSd, OpSn, OpSm, Vmuls);
3309 }
3310
vmuld(const Operand * OpDd,const Operand * OpDn,const Operand * OpDm,CondARM32::Cond Cond)3311 void AssemblerARM32::vmuld(const Operand *OpDd, const Operand *OpDn,
3312 const Operand *OpDm, CondARM32::Cond Cond) {
3313 // VMUL (floating-point) - ARM section A8.8.351, encoding A2:
3314 // vmul<c>.f64 <Dd>, <Dn>, <Dm>
3315 //
3316 // cccc11100D10nnnndddd101sN0M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn,
3317 // and Mmmmm=Rm.
3318 constexpr const char *Vmuld = "vmuld";
3319 constexpr IValueT VmuldOpcode = B21;
3320 emitVFPddd(Cond, VmuldOpcode, OpDd, OpDn, OpDm, Vmuld);
3321 }
3322
vmulqi(Type ElmtTy,const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3323 void AssemblerARM32::vmulqi(Type ElmtTy, const Operand *OpQd,
3324 const Operand *OpQn, const Operand *OpQm) {
3325 // VMUL, VMULL (integer and polynomial) - ARM section A8.8.350, encoding A1:
3326 // vmul<c>.<dt> <Qd>, <Qn>, <Qm>
3327 //
3328 // 111100100Dssnnn0ddd01001NqM1mmm0 where Dddd=Qd, Nnnn=Qn, Mmmm=Qm, and
3329 // dt in [i8, i16, i32] where ss is the index.
3330 assert(isScalarIntegerType(ElmtTy) &&
3331 "vmulqi expects vector with integer element type");
3332 assert(ElmtTy != IceType_i64 && "vmulqi on i64 vector not allowed");
3333 constexpr const char *Vmulqi = "vmulqi";
3334 constexpr IValueT VmulqiOpcode = B11 | B8 | B4;
3335 emitSIMDqqq(VmulqiOpcode, ElmtTy, OpQd, OpQn, OpQm, Vmulqi);
3336 }
3337
vmulh(Type ElmtTy,const Operand * OpQd,const Operand * OpQn,const Operand * OpQm,bool Unsigned)3338 void AssemblerARM32::vmulh(Type ElmtTy, const Operand *OpQd,
3339 const Operand *OpQn, const Operand *OpQm,
3340 bool Unsigned) {
3341 // Pseudo-instruction for multiplying the corresponding elements in the lower
3342 // halves of two quadword vectors, and returning the high halves.
3343
3344 // VMULL (integer and polynomial) - ARMv7-A/R section A8.6.337, encoding A1:
3345 // VMUL<c>.<dt> <Dd>, <Dn>, <Dm>
3346 //
3347 // 1111001U1Dssnnnndddd11o0N0M0mmmm
3348 assert(isScalarIntegerType(ElmtTy) &&
3349 "vmull expects vector with integer element type");
3350 assert(ElmtTy != IceType_i64 && "vmull on i64 vector not allowed");
3351 constexpr const char *Vmull = "vmull";
3352
3353 constexpr IValueT ElmtShift = 20;
3354 const IValueT ElmtSize = encodeElmtType(ElmtTy);
3355 assert(Utils::IsUint(2, ElmtSize));
3356
3357 const IValueT VmullOpcode =
3358 B25 | (Unsigned ? B24 : 0) | B23 | (B20) | B11 | B10;
3359
3360 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vmull);
3361 const IValueT Qn = encodeQRegister(OpQn, "Qn", Vmull);
3362 const IValueT Qm = encodeQRegister(OpQm, "Qm", Vmull);
3363
3364 const IValueT Dd = mapQRegToDReg(Qd);
3365 const IValueT Dn = mapQRegToDReg(Qn);
3366 const IValueT Dm = mapQRegToDReg(Qm);
3367
3368 constexpr bool UseQRegs = false;
3369 constexpr bool IsFloatTy = false;
3370 emitSIMDBase(VmullOpcode | (ElmtSize << ElmtShift), Dd, Dn, Dm, UseQRegs,
3371 IsFloatTy);
3372
3373 // Shift and narrow to obtain high halves.
3374 constexpr IValueT VshrnOpcode = B25 | B23 | B11 | B4;
3375 const IValueT Imm6 = encodeSIMDShiftImm6(ST_Vshr, IceType_i16, 16);
3376 constexpr IValueT ImmShift = 16;
3377
3378 emitSIMDBase(VshrnOpcode | (Imm6 << ImmShift), Dd, 0, Dd, UseQRegs,
3379 IsFloatTy);
3380 }
3381
vmlap(Type ElmtTy,const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3382 void AssemblerARM32::vmlap(Type ElmtTy, const Operand *OpQd,
3383 const Operand *OpQn, const Operand *OpQm) {
3384 // Pseudo-instruction for multiplying the corresponding elements in the lower
3385 // halves of two quadword vectors, and pairwise-adding the results.
3386
3387 // VMULL (integer and polynomial) - ARM section A8.8.350, encoding A1:
3388 // vmull<c>.<dt> <Qd>, <Qn>, <Qm>
3389 //
3390 // 1111001U1Dssnnnndddd11o0N0M0mmmm
3391 assert(isScalarIntegerType(ElmtTy) &&
3392 "vmull expects vector with integer element type");
3393 assert(ElmtTy != IceType_i64 && "vmull on i64 vector not allowed");
3394 constexpr const char *Vmull = "vmull";
3395
3396 constexpr IValueT ElmtShift = 20;
3397 const IValueT ElmtSize = encodeElmtType(ElmtTy);
3398 assert(Utils::IsUint(2, ElmtSize));
3399
3400 bool Unsigned = false;
3401 const IValueT VmullOpcode =
3402 B25 | (Unsigned ? B24 : 0) | B23 | (B20) | B11 | B10;
3403
3404 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmull));
3405 const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmull));
3406 const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmull));
3407
3408 constexpr bool UseQRegs = false;
3409 constexpr bool IsFloatTy = false;
3410 emitSIMDBase(VmullOpcode | (ElmtSize << ElmtShift), Dd, Dn, Dm, UseQRegs,
3411 IsFloatTy);
3412
3413 // VPADD - ARM section A8.8.280, encoding A1:
3414 // vpadd.<dt> <Dd>, <Dm>, <Dn>
3415 //
3416 // 111100100Dssnnnndddd1011NQM1mmmm where Ddddd=<Dd>, Mmmmm=<Dm>, and
3417 // Nnnnn=<Dn> and ss is the encoding of <dt>.
3418 assert(ElmtTy != IceType_i64 && "vpadd doesn't allow i64!");
3419 const IValueT VpaddOpcode =
3420 B25 | B11 | B9 | B8 | B4 | ((encodeElmtType(ElmtTy) + 1) << 20);
3421 emitSIMDBase(VpaddOpcode, Dd, Dd, Dd + 1, UseQRegs, IsFloatTy);
3422 }
3423
vdup(Type ElmtTy,const Operand * OpQd,const Operand * OpQn,IValueT Idx)3424 void AssemblerARM32::vdup(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
3425 IValueT Idx) {
3426 // VDUP (scalar) - ARMv7-A/R section A8.6.302, encoding A1:
3427 // VDUP<c>.<size> <Qd>, <Dm[x]>
3428 //
3429 // 111100111D11iiiiddd011000QM0mmmm where Dddd=<Qd>, Mmmmm=<Dm>, and
3430 // iiii=imm4 encodes <size> and [x].
3431 constexpr const char *Vdup = "vdup";
3432
3433 const IValueT VdupOpcode = B25 | B24 | B23 | B21 | B20 | B11 | B10;
3434
3435 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vdup));
3436 const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vdup));
3437
3438 constexpr bool UseQRegs = true;
3439 constexpr bool IsFloatTy = false;
3440
3441 IValueT Imm4 = 0;
3442 bool Lower = true;
3443 switch (ElmtTy) {
3444 case IceType_i8:
3445 assert(Idx < 16);
3446 Lower = Idx < 8;
3447 Imm4 = 1 | ((Idx & 0x7) << 1);
3448 break;
3449 case IceType_i16:
3450 assert(Idx < 8);
3451 Lower = Idx < 4;
3452 Imm4 = 2 | ((Idx & 0x3) << 2);
3453 break;
3454 case IceType_i32:
3455 case IceType_f32:
3456 assert(Idx < 4);
3457 Lower = Idx < 2;
3458 Imm4 = 4 | ((Idx & 0x1) << 3);
3459 break;
3460 default:
3461 assert(false && "vdup only supports 8, 16, and 32-bit elements");
3462 break;
3463 }
3464
3465 emitSIMDBase(VdupOpcode, Dd, Imm4, Dn + (Lower ? 0 : 1), UseQRegs, IsFloatTy);
3466 }
3467
vzip(Type ElmtTy,const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3468 void AssemblerARM32::vzip(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
3469 const Operand *OpQm) {
3470 // Pseudo-instruction which interleaves the elements of the lower halves of
3471 // two quadword registers.
3472
3473 // Vzip - ARMv7-A/R section A8.6.410, encoding A1:
3474 // VZIP<c>.<size> <Dd>, <Dm>
3475 //
3476 // 111100111D11ss10dddd00011QM0mmmm where Ddddd=<Dd>, Mmmmm=<Dm>, and
3477 // ss=<size>
3478 assert(ElmtTy != IceType_i64 && "vzip on i64 vector not allowed");
3479
3480 constexpr const char *Vzip = "vzip";
3481 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vzip));
3482 const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vzip));
3483 const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vzip));
3484
3485 constexpr bool UseQRegs = false;
3486 constexpr bool IsFloatTy = false;
3487
3488 // VMOV Dd, Dm
3489 // 111100100D10mmmmdddd0001MQM1mmmm
3490 constexpr IValueT VmovOpcode = B25 | B21 | B8 | B4;
3491
3492 // Copy lower half of second source to upper half of destination.
3493 emitSIMDBase(VmovOpcode, Dd + 1, Dm, Dm, UseQRegs, IsFloatTy);
3494
3495 // Copy lower half of first source to lower half of destination.
3496 if (Dd != Dn)
3497 emitSIMDBase(VmovOpcode, Dd, Dn, Dn, UseQRegs, IsFloatTy);
3498
3499 constexpr IValueT ElmtShift = 18;
3500 const IValueT ElmtSize = encodeElmtType(ElmtTy);
3501 assert(Utils::IsUint(2, ElmtSize));
3502
3503 if (ElmtTy != IceType_i32 && ElmtTy != IceType_f32) {
3504 constexpr IValueT VzipOpcode = B25 | B24 | B23 | B21 | B20 | B17 | B8 | B7;
3505 // Zip the lower and upper half of destination.
3506 emitSIMDBase(VzipOpcode | (ElmtSize << ElmtShift), Dd, 0, Dd + 1, UseQRegs,
3507 IsFloatTy);
3508 } else {
3509 constexpr IValueT VtrnOpcode = B25 | B24 | B23 | B21 | B20 | B17 | B7;
3510 emitSIMDBase(VtrnOpcode | (ElmtSize << ElmtShift), Dd, 0, Dd + 1, UseQRegs,
3511 IsFloatTy);
3512 }
3513 }
3514
vmulqf(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3515 void AssemblerARM32::vmulqf(const Operand *OpQd, const Operand *OpQn,
3516 const Operand *OpQm) {
3517 // VMUL (floating-point) - ARM section A8.8.351, encoding A1:
3518 // vmul.f32 <Qd>, <Qn>, <Qm>
3519 //
3520 // 111100110D00nnn0ddd01101MqM1mmm0 where Dddd=Qd, Nnnn=Qn, and Mmmm=Qm.
3521 assert(OpQd->getType() == IceType_v4f32 && "vmulqf expects type <4 x float>");
3522 constexpr const char *Vmulqf = "vmulqf";
3523 constexpr IValueT VmulqfOpcode = B24 | B11 | B8 | B4;
3524 constexpr bool IsFloatTy = true;
3525 emitSIMDqqqBase(VmulqfOpcode, OpQd, OpQn, OpQm, IsFloatTy, Vmulqf);
3526 }
3527
vmvnq(const Operand * OpQd,const Operand * OpQm)3528 void AssemblerARM32::vmvnq(const Operand *OpQd, const Operand *OpQm) {
3529 // VMVN (integer) - ARM section A8.8.354, encoding A1:
3530 // vmvn <Qd>, <Qm>
3531 //
3532 // 111100111D110000dddd01011QM0mmmm where Dddd=Qd, Mmmm=Qm, and 1=Q.
3533 // TODO(jpp) xxx: unify
3534 constexpr const char *Vmvn = "vmvn";
3535 constexpr IValueT VmvnOpcode = B24 | B23 | B21 | B20 | B10 | B8 | B7;
3536 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vmvn);
3537 constexpr IValueT Qn = 0;
3538 const IValueT Qm = encodeQRegister(OpQm, "Qm", Vmvn);
3539 constexpr bool UseQRegs = true;
3540 constexpr bool IsFloat = false;
3541 emitSIMDBase(VmvnOpcode, mapQRegToDReg(Qd), mapQRegToDReg(Qn),
3542 mapQRegToDReg(Qm), UseQRegs, IsFloat);
3543 }
3544
vmovlq(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3545 void AssemblerARM32::vmovlq(const Operand *OpQd, const Operand *OpQn,
3546 const Operand *OpQm) {
3547 // Pseudo-instruction to copy the first source operand and insert the lower
3548 // half of the second operand into the lower half of the destination.
3549
3550 // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
3551 // VMOV<c> <Dd>, <Dm>
3552 //
3553 // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
3554
3555 constexpr const char *Vmov = "vmov";
3556 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
3557 const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
3558 const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
3559
3560 constexpr bool UseQRegs = false;
3561 constexpr bool IsFloat = false;
3562
3563 const IValueT VmovOpcode = B25 | B21 | B8 | B4;
3564
3565 if (Dd != Dm)
3566 emitSIMDBase(VmovOpcode, Dd, Dm, Dm, UseQRegs, IsFloat);
3567 if (Dd + 1 != Dn + 1)
3568 emitSIMDBase(VmovOpcode, Dd + 1, Dn + 1, Dn + 1, UseQRegs, IsFloat);
3569 }
3570
vmovhq(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3571 void AssemblerARM32::vmovhq(const Operand *OpQd, const Operand *OpQn,
3572 const Operand *OpQm) {
3573 // Pseudo-instruction to copy the first source operand and insert the high
3574 // half of the second operand into the high half of the destination.
3575
3576 // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
3577 // VMOV<c> <Dd>, <Dm>
3578 //
3579 // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
3580
3581 constexpr const char *Vmov = "vmov";
3582 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
3583 const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
3584 const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
3585
3586 constexpr bool UseQRegs = false;
3587 constexpr bool IsFloat = false;
3588
3589 const IValueT VmovOpcode = B25 | B21 | B8 | B4;
3590
3591 if (Dd != Dn)
3592 emitSIMDBase(VmovOpcode, Dd, Dn, Dn, UseQRegs, IsFloat);
3593 if (Dd + 1 != Dm + 1)
3594 emitSIMDBase(VmovOpcode, Dd + 1, Dm + 1, Dm + 1, UseQRegs, IsFloat);
3595 }
3596
vmovhlq(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3597 void AssemblerARM32::vmovhlq(const Operand *OpQd, const Operand *OpQn,
3598 const Operand *OpQm) {
3599 // Pseudo-instruction to copy the first source operand and insert the high
3600 // half of the second operand into the lower half of the destination.
3601
3602 // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
3603 // VMOV<c> <Dd>, <Dm>
3604 //
3605 // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
3606
3607 constexpr const char *Vmov = "vmov";
3608 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
3609 const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
3610 const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
3611
3612 constexpr bool UseQRegs = false;
3613 constexpr bool IsFloat = false;
3614
3615 const IValueT VmovOpcode = B25 | B21 | B8 | B4;
3616
3617 if (Dd != Dm + 1)
3618 emitSIMDBase(VmovOpcode, Dd, Dm + 1, Dm + 1, UseQRegs, IsFloat);
3619 if (Dd + 1 != Dn + 1)
3620 emitSIMDBase(VmovOpcode, Dd + 1, Dn + 1, Dn + 1, UseQRegs, IsFloat);
3621 }
3622
vmovlhq(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3623 void AssemblerARM32::vmovlhq(const Operand *OpQd, const Operand *OpQn,
3624 const Operand *OpQm) {
3625 // Pseudo-instruction to copy the first source operand and insert the lower
3626 // half of the second operand into the high half of the destination.
3627
3628 // VMOV (register) - ARMv7-A/R section A8.6.327, encoding A1:
3629 // VMOV<c> <Dd>, <Dm>
3630 //
3631 // 111100111D110000ddd001011QM0mmm0 where Dddd=Qd, Mmmm=Qm, and Q=0.
3632
3633 constexpr const char *Vmov = "vmov";
3634 const IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Qd", Vmov));
3635 const IValueT Dn = mapQRegToDReg(encodeQRegister(OpQn, "Qn", Vmov));
3636 const IValueT Dm = mapQRegToDReg(encodeQRegister(OpQm, "Qm", Vmov));
3637
3638 constexpr bool UseQRegs = false;
3639 constexpr bool IsFloat = false;
3640
3641 const IValueT VmovOpcode = B25 | B21 | B8 | B4;
3642
3643 if (Dd + 1 != Dm)
3644 emitSIMDBase(VmovOpcode, Dd + 1, Dm, Dm, UseQRegs, IsFloat);
3645 if (Dd != Dn)
3646 emitSIMDBase(VmovOpcode, Dd, Dn, Dn, UseQRegs, IsFloat);
3647 }
3648
vnegqs(Type ElmtTy,const Operand * OpQd,const Operand * OpQm)3649 void AssemblerARM32::vnegqs(Type ElmtTy, const Operand *OpQd,
3650 const Operand *OpQm) {
3651 // VNEG - ARM section A8.8.355, encoding A1:
3652 // vneg.<dt> <Qd>, <Qm>
3653 //
3654 // 111111111D11ss01dddd0F111QM0mmmm where Dddd=Qd, and Mmmm=Qm, and:
3655 // * dt=s8 -> 00=ss, 0=F
3656 // * dt=s16 -> 01=ss, 0=F
3657 // * dt=s32 -> 10=ss, 0=F
3658 // * dt=s32 -> 10=ss, 1=F
3659 constexpr const char *Vneg = "vneg";
3660 constexpr IValueT VnegOpcode = B24 | B23 | B21 | B20 | B16 | B9 | B8 | B7;
3661 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vneg);
3662 constexpr IValueT Qn = 0;
3663 const IValueT Qm = encodeQRegister(OpQm, "Qm", Vneg);
3664 constexpr bool UseQRegs = true;
3665 constexpr IValueT ElmtShift = 18;
3666 const IValueT ElmtSize = encodeElmtType(ElmtTy);
3667 assert(Utils::IsUint(2, ElmtSize));
3668 emitSIMDBase(VnegOpcode | (ElmtSize << ElmtShift), mapQRegToDReg(Qd),
3669 mapQRegToDReg(Qn), mapQRegToDReg(Qm), UseQRegs,
3670 isFloatingType(ElmtTy));
3671 }
3672
vorrq(const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)3673 void AssemblerARM32::vorrq(const Operand *OpQd, const Operand *OpQm,
3674 const Operand *OpQn) {
3675 // VORR (register) - ARM section A8.8.360, encoding A1:
3676 // vorr <Qd>, <Qn>, <Qm>
3677 //
3678 // 111100100D10nnn0ddd00001N1M1mmm0 where Dddd=OpQd, Nnnn=OpQm, and Mmmm=OpQm.
3679 constexpr const char *Vorrq = "vorrq";
3680 constexpr IValueT VorrqOpcode = B21 | B8 | B4;
3681 constexpr Type ElmtTy = IceType_i8;
3682 emitSIMDqqq(VorrqOpcode, ElmtTy, OpQd, OpQm, OpQn, Vorrq);
3683 }
3684
vstrd(const Operand * OpDd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)3685 void AssemblerARM32::vstrd(const Operand *OpDd, const Operand *OpAddress,
3686 CondARM32::Cond Cond, const TargetInfo &TInfo) {
3687 // VSTR - ARM section A8.8.413, encoding A1:
3688 // vstr<c> <Dd>, [<Rn>{, #+/-<Imm>}]
3689 //
3690 // cccc1101UD00nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
3691 // iiiiiiii=abs(Imm >> 2), and U=1 if Imm>=0.
3692 constexpr const char *Vstrd = "vstrd";
3693 IValueT Dd = encodeDRegister(OpDd, "Dd", Vstrd);
3694 assert(CondARM32::isDefined(Cond));
3695 IValueT Address;
3696 IValueT AddressEncoding =
3697 encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
3698 (void)AddressEncoding;
3699 assert(AddressEncoding == EncodedAsImmRegOffset);
3700 IValueT Encoding = B27 | B26 | B24 | B11 | B9 | B8 |
3701 (encodeCondition(Cond) << kConditionShift) |
3702 (getYInRegYXXXX(Dd) << 22) |
3703 (getXXXXInRegYXXXX(Dd) << 12) | Address;
3704 emitInst(Encoding);
3705 }
3706
vstrq(const Operand * OpQd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)3707 void AssemblerARM32::vstrq(const Operand *OpQd, const Operand *OpAddress,
3708 CondARM32::Cond Cond, const TargetInfo &TInfo) {
3709 // This is a pseudo-instruction which stores 64-bit data into a quadword
3710 // vector register. It is implemented by storing into the lower doubleword.
3711
3712 // VSTR - ARM section A8.8.413, encoding A1:
3713 // vstr<c> <Dd>, [<Rn>{, #+/-<Imm>}]
3714 //
3715 // cccc1101UD00nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
3716 // iiiiiiii=abs(Imm >> 2), and U=1 if Imm>=0.
3717 constexpr const char *Vstrd = "vstrd";
3718 IValueT Dd = mapQRegToDReg(encodeQRegister(OpQd, "Dd", Vstrd));
3719 assert(CondARM32::isDefined(Cond));
3720 IValueT Address;
3721 IValueT AddressEncoding =
3722 encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
3723 (void)AddressEncoding;
3724 assert(AddressEncoding == EncodedAsImmRegOffset);
3725 IValueT Encoding = B27 | B26 | B24 | B11 | B9 | B8 |
3726 (encodeCondition(Cond) << kConditionShift) |
3727 (getYInRegYXXXX(Dd) << 22) |
3728 (getXXXXInRegYXXXX(Dd) << 12) | Address;
3729 emitInst(Encoding);
3730 }
3731
vstrs(const Operand * OpSd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetInfo & TInfo)3732 void AssemblerARM32::vstrs(const Operand *OpSd, const Operand *OpAddress,
3733 CondARM32::Cond Cond, const TargetInfo &TInfo) {
3734 // VSTR - ARM section A8.8.413, encoding A2:
3735 // vstr<c> <Sd>, [<Rn>{, #+/-<imm>]]
3736 //
3737 // cccc1101UD01nnnndddd1010iiiiiiii where cccc=Cond, nnnn=Rn, ddddD=Sd,
3738 // iiiiiiii=abs(Opcode), and U=1 if Opcode >= 0;
3739 constexpr const char *Vstrs = "vstrs";
3740 IValueT Sd = encodeSRegister(OpSd, "Sd", Vstrs);
3741 assert(CondARM32::isDefined(Cond));
3742 IValueT Address;
3743 IValueT AddressEncoding =
3744 encodeAddress(OpAddress, Address, TInfo, RotatedImm8Div4Address);
3745 (void)AddressEncoding;
3746 assert(AddressEncoding == EncodedAsImmRegOffset);
3747 IValueT Encoding =
3748 B27 | B26 | B24 | B11 | B9 | (encodeCondition(Cond) << kConditionShift) |
3749 (getYInRegXXXXY(Sd) << 22) | (getXXXXInRegXXXXY(Sd) << 12) | Address;
3750 emitInst(Encoding);
3751 }
3752
vst1qr(size_t ElmtSize,const Operand * OpQd,const Operand * OpAddress,const TargetInfo & TInfo)3753 void AssemblerARM32::vst1qr(size_t ElmtSize, const Operand *OpQd,
3754 const Operand *OpAddress, const TargetInfo &TInfo) {
3755 // VST1 (multiple single elements) - ARM section A8.8.404, encoding A1:
3756 // vst1.<size> <Qd>, [<Rn>]
3757 //
3758 // 111101000D00nnnnddd0ttttssaammmm where tttt=DRegListSize2, Dddd=Qd,
3759 // nnnn=Rn, aa=0 (use default alignment), size=ElmtSize, and ss is the
3760 // encoding of ElmtSize.
3761 constexpr const char *Vst1qr = "vst1qr";
3762 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vst1qr);
3763 const IValueT Dd = mapQRegToDReg(Qd);
3764 IValueT Address;
3765 if (encodeAddress(OpAddress, Address, TInfo, NoImmOffsetAddress) !=
3766 EncodedAsImmRegOffset)
3767 llvm::report_fatal_error(std::string(Vst1qr) + ": malform memory address");
3768 const IValueT Rn = mask(Address, kRnShift, 4);
3769 constexpr IValueT Rm = RegARM32::Reg_pc;
3770 constexpr IValueT Opcode = B26;
3771 constexpr IValueT Align = 0; // use default alignment.
3772 emitVMem1Op(Opcode, Dd, Rn, Rm, DRegListSize2, ElmtSize, Align, Vst1qr);
3773 }
3774
vst1(size_t ElmtSize,const Operand * OpQd,const Operand * OpAddress,const TargetInfo & TInfo)3775 void AssemblerARM32::vst1(size_t ElmtSize, const Operand *OpQd,
3776 const Operand *OpAddress, const TargetInfo &TInfo) {
3777
3778 // This is a pseudo-instruction for storing a single element of a quadword
3779 // vector. For 64-bit the lower doubleword vector is stored.
3780
3781 if (ElmtSize == 64) {
3782 return vstrq(OpQd, OpAddress, Ice::CondARM32::AL, TInfo);
3783 }
3784
3785 // VST1 (single element from one lane) - ARMv7-A/R section A8.6.392, encoding
3786 // A1:
3787 // VST1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>
3788 //
3789 // 111101001D00nnnnddd0ss00aaaammmm where Dddd=Qd, nnnn=Rn,
3790 // aaaa=0 (use default alignment), size=ElmtSize, and ss is the
3791 // encoding of ElmtSize.
3792 constexpr const char *Vst1qr = "vst1qr";
3793 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vst1qr);
3794 const IValueT Dd = mapQRegToDReg(Qd);
3795 IValueT Address;
3796 if (encodeAddress(OpAddress, Address, TInfo, NoImmOffsetAddress) !=
3797 EncodedAsImmRegOffset)
3798 llvm::report_fatal_error(std::string(Vst1qr) + ": malform memory address");
3799 const IValueT Rn = mask(Address, kRnShift, 4);
3800 constexpr IValueT Rm = RegARM32::Reg_pc;
3801 constexpr IValueT Opcode = B26 | B23;
3802 constexpr IValueT Align = 0; // use default alignment.
3803 emitVMem1Op(Opcode, Dd, Rn, Rm, ElmtSize, Align, Vst1qr);
3804 }
3805
vsubs(const Operand * OpSd,const Operand * OpSn,const Operand * OpSm,CondARM32::Cond Cond)3806 void AssemblerARM32::vsubs(const Operand *OpSd, const Operand *OpSn,
3807 const Operand *OpSm, CondARM32::Cond Cond) {
3808 // VSUB (floating-point) - ARM section A8.8.415, encoding A2:
3809 // vsub<c>.f32 <Sd>, <Sn>, <Sm>
3810 //
3811 // cccc11100D11nnnndddd101sN1M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn,
3812 // and mmmmM=Rm.
3813 constexpr const char *Vsubs = "vsubs";
3814 constexpr IValueT VsubsOpcode = B21 | B20 | B6;
3815 emitVFPsss(Cond, VsubsOpcode, OpSd, OpSn, OpSm, Vsubs);
3816 }
3817
vsubd(const Operand * OpDd,const Operand * OpDn,const Operand * OpDm,CondARM32::Cond Cond)3818 void AssemblerARM32::vsubd(const Operand *OpDd, const Operand *OpDn,
3819 const Operand *OpDm, CondARM32::Cond Cond) {
3820 // VSUB (floating-point) - ARM section A8.8.415, encoding A2:
3821 // vsub<c>.f64 <Dd>, <Dn>, <Dm>
3822 //
3823 // cccc11100D11nnnndddd101sN1M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn,
3824 // and Mmmmm=Rm.
3825 constexpr const char *Vsubd = "vsubd";
3826 constexpr IValueT VsubdOpcode = B21 | B20 | B6;
3827 emitVFPddd(Cond, VsubdOpcode, OpDd, OpDn, OpDm, Vsubd);
3828 }
3829
vqaddqi(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)3830 void AssemblerARM32::vqaddqi(Type ElmtTy, const Operand *OpQd,
3831 const Operand *OpQm, const Operand *OpQn) {
3832 // VQADD (integer) - ARM section A8.6.369, encoding A1:
3833 // vqadd<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
3834 //
3835 // 111100100Dssnnn0ddd00000N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
3836 // size is 8, 16, 32, or 64.
3837 assert(isScalarIntegerType(ElmtTy) &&
3838 "vqaddqi expects vector with integer element type");
3839 constexpr const char *Vqaddqi = "vqaddqi";
3840 constexpr IValueT VqaddqiOpcode = B4;
3841 emitSIMDqqq(VqaddqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqaddqi);
3842 }
3843
vqaddqu(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)3844 void AssemblerARM32::vqaddqu(Type ElmtTy, const Operand *OpQd,
3845 const Operand *OpQm, const Operand *OpQn) {
3846 // VQADD (integer) - ARM section A8.6.369, encoding A1:
3847 // vqadd<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
3848 //
3849 // 111100110Dssnnn0ddd00000N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
3850 // size is 8, 16, 32, or 64.
3851 assert(isScalarIntegerType(ElmtTy) &&
3852 "vqaddqu expects vector with integer element type");
3853 constexpr const char *Vqaddqu = "vqaddqu";
3854 constexpr IValueT VqaddquOpcode = B24 | B4;
3855 emitSIMDqqq(VqaddquOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqaddqu);
3856 }
3857
vqsubqi(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)3858 void AssemblerARM32::vqsubqi(Type ElmtTy, const Operand *OpQd,
3859 const Operand *OpQm, const Operand *OpQn) {
3860 // VQSUB (integer) - ARM section A8.6.369, encoding A1:
3861 // vqsub<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
3862 //
3863 // 111100100Dssnnn0ddd00010N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
3864 // size is 8, 16, 32, or 64.
3865 assert(isScalarIntegerType(ElmtTy) &&
3866 "vqsubqi expects vector with integer element type");
3867 constexpr const char *Vqsubqi = "vqsubqi";
3868 constexpr IValueT VqsubqiOpcode = B9 | B4;
3869 emitSIMDqqq(VqsubqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqsubqi);
3870 }
3871
vqsubqu(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)3872 void AssemblerARM32::vqsubqu(Type ElmtTy, const Operand *OpQd,
3873 const Operand *OpQm, const Operand *OpQn) {
3874 // VQSUB (integer) - ARM section A8.6.369, encoding A1:
3875 // vqsub<c><q>.s<size> {<Qd>,} <Qn>, <Qm>
3876 //
3877 // 111100110Dssnnn0ddd00010N1M1mmm0 where Dddd=OpQd, Nnnn=OpQn, Mmmm=OpQm,
3878 // size is 8, 16, 32, or 64.
3879 assert(isScalarIntegerType(ElmtTy) &&
3880 "vqsubqu expects vector with integer element type");
3881 constexpr const char *Vqsubqu = "vqsubqu";
3882 constexpr IValueT VqsubquOpcode = B24 | B9 | B4;
3883 emitSIMDqqq(VqsubquOpcode, ElmtTy, OpQd, OpQm, OpQn, Vqsubqu);
3884 }
3885
vsubqi(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)3886 void AssemblerARM32::vsubqi(Type ElmtTy, const Operand *OpQd,
3887 const Operand *OpQm, const Operand *OpQn) {
3888 // VSUB (integer) - ARM section A8.8.414, encoding A1:
3889 // vsub.<dt> <Qd>, <Qn>, <Qm>
3890 //
3891 // 111100110Dssnnn0ddd01000N1M0mmm0 where Dddd=OpQd, Nnnn=OpQm, Mmmm=OpQm,
3892 // and dt in [i8, i16, i32, i64] where ss is the index.
3893 assert(isScalarIntegerType(ElmtTy) &&
3894 "vsubqi expects vector with integer element type");
3895 constexpr const char *Vsubqi = "vsubqi";
3896 constexpr IValueT VsubqiOpcode = B24 | B11;
3897 emitSIMDqqq(VsubqiOpcode, ElmtTy, OpQd, OpQm, OpQn, Vsubqi);
3898 }
3899
vqmovn2(Type DestElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn,bool Unsigned,bool Saturating)3900 void AssemblerARM32::vqmovn2(Type DestElmtTy, const Operand *OpQd,
3901 const Operand *OpQm, const Operand *OpQn,
3902 bool Unsigned, bool Saturating) {
3903 // Pseudo-instruction for packing two quadword vectors into one quadword
3904 // vector, narrowing each element using saturation or truncation.
3905
3906 // VQMOVN - ARMv7-A/R section A8.6.361, encoding A1:
3907 // V{Q}MOVN{U}N<c>.<type><size> <Dd>, <Qm>
3908 //
3909 // 111100111D11ss10dddd0010opM0mmm0 where Ddddd=OpQd, op = 10, Mmmm=OpQm,
3910 // ss is 00 (16-bit), 01 (32-bit), or 10 (64-bit).
3911
3912 assert(DestElmtTy != IceType_i64 &&
3913 "vmovn doesn't allow i64 destination vector elements!");
3914
3915 constexpr const char *Vqmovn = "vqmovn";
3916 constexpr bool UseQRegs = false;
3917 constexpr bool IsFloatTy = false;
3918 const IValueT Qd = encodeQRegister(OpQd, "Qd", Vqmovn);
3919 const IValueT Qm = encodeQRegister(OpQm, "Qm", Vqmovn);
3920 const IValueT Qn = encodeQRegister(OpQn, "Qn", Vqmovn);
3921 const IValueT Dd = mapQRegToDReg(Qd);
3922 const IValueT Dm = mapQRegToDReg(Qm);
3923 const IValueT Dn = mapQRegToDReg(Qn);
3924
3925 IValueT VqmovnOpcode = B25 | B24 | B23 | B21 | B20 | B17 | B9 |
3926 (Saturating ? (Unsigned ? B6 : B7) : 0);
3927
3928 constexpr IValueT ElmtShift = 18;
3929 VqmovnOpcode |= (encodeElmtType(DestElmtTy) << ElmtShift);
3930
3931 if (Qm != Qd) {
3932 // Narrow second source operand to upper half of destination.
3933 emitSIMDBase(VqmovnOpcode, Dd + 1, 0, Dn, UseQRegs, IsFloatTy);
3934 // Narrow first source operand to lower half of destination.
3935 emitSIMDBase(VqmovnOpcode, Dd + 0, 0, Dm, UseQRegs, IsFloatTy);
3936 } else if (Qn != Qd) {
3937 // Narrow first source operand to lower half of destination.
3938 emitSIMDBase(VqmovnOpcode, Dd + 0, 0, Dm, UseQRegs, IsFloatTy);
3939 // Narrow second source operand to upper half of destination.
3940 emitSIMDBase(VqmovnOpcode, Dd + 1, 0, Dn, UseQRegs, IsFloatTy);
3941 } else {
3942 // Narrow first source operand to lower half of destination.
3943 emitSIMDBase(VqmovnOpcode, Dd, 0, Dm, UseQRegs, IsFloatTy);
3944
3945 // VMOV Dd, Dm
3946 // 111100100D10mmmmdddd0001MQM1mmmm
3947 const IValueT VmovOpcode = B25 | B21 | B8 | B4;
3948
3949 emitSIMDBase(VmovOpcode, Dd + 1, Dd, Dd, UseQRegs, IsFloatTy);
3950 }
3951 }
3952
vsubqf(const Operand * OpQd,const Operand * OpQn,const Operand * OpQm)3953 void AssemblerARM32::vsubqf(const Operand *OpQd, const Operand *OpQn,
3954 const Operand *OpQm) {
3955 // VSUB (floating-point) - ARM section A8.8.415, Encoding A1:
3956 // vsub.f32 <Qd>, <Qn>, <Qm>
3957 //
3958 // 111100100D10nnn0ddd01101N1M0mmm0 where Dddd=Qd, Nnnn=Qn, and Mmmm=Qm.
3959 assert(OpQd->getType() == IceType_v4f32 && "vsubqf expects type <4 x float>");
3960 constexpr const char *Vsubqf = "vsubqf";
3961 constexpr IValueT VsubqfOpcode = B21 | B11 | B8;
3962 emitSIMDqqq(VsubqfOpcode, IceType_f32, OpQd, OpQn, OpQm, Vsubqf);
3963 }
3964
emitVStackOp(CondARM32::Cond Cond,IValueT Opcode,const Variable * OpBaseReg,SizeT NumConsecRegs)3965 void AssemblerARM32::emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
3966 const Variable *OpBaseReg,
3967 SizeT NumConsecRegs) {
3968 const IValueT BaseReg = getEncodedSRegNum(OpBaseReg);
3969 const IValueT DLastBit = mask(BaseReg, 0, 1); // Last bit of base register.
3970 const IValueT Rd = mask(BaseReg, 1, 4); // Top 4 bits of base register.
3971 assert(0 < NumConsecRegs);
3972 (void)VpushVpopMaxConsecRegs;
3973 assert(NumConsecRegs <= VpushVpopMaxConsecRegs);
3974 assert((BaseReg + NumConsecRegs) <= RegARM32::getNumSRegs());
3975 assert(CondARM32::isDefined(Cond));
3976 const IValueT Encoding = Opcode | (Cond << kConditionShift) | DLastBit |
3977 (Rd << kRdShift) | NumConsecRegs;
3978 emitInst(Encoding);
3979 }
3980
vpop(const Variable * OpBaseReg,SizeT NumConsecRegs,CondARM32::Cond Cond)3981 void AssemblerARM32::vpop(const Variable *OpBaseReg, SizeT NumConsecRegs,
3982 CondARM32::Cond Cond) {
3983 // Note: Current implementation assumes that OpBaseReg is defined using S
3984 // registers. It doesn't implement the D register form.
3985 //
3986 // VPOP - ARM section A8.8.367, encoding A2:
3987 // vpop<c> <RegList>
3988 //
3989 // cccc11001D111101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and
3990 // iiiiiiii=NumConsecRegs.
3991 constexpr IValueT VpopOpcode =
3992 B27 | B26 | B23 | B21 | B20 | B19 | B18 | B16 | B11 | B9;
3993 emitVStackOp(Cond, VpopOpcode, OpBaseReg, NumConsecRegs);
3994 }
3995
vpush(const Variable * OpBaseReg,SizeT NumConsecRegs,CondARM32::Cond Cond)3996 void AssemblerARM32::vpush(const Variable *OpBaseReg, SizeT NumConsecRegs,
3997 CondARM32::Cond Cond) {
3998 // Note: Current implementation assumes that OpBaseReg is defined using S
3999 // registers. It doesn't implement the D register form.
4000 //
4001 // VPUSH - ARM section A8.8.368, encoding A2:
4002 // vpush<c> <RegList>
4003 //
4004 // cccc11010D101101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and
4005 // iiiiiiii=NumConsecRegs.
4006 constexpr IValueT VpushOpcode =
4007 B27 | B26 | B24 | B21 | B19 | B18 | B16 | B11 | B9;
4008 emitVStackOp(Cond, VpushOpcode, OpBaseReg, NumConsecRegs);
4009 }
4010
vshlqi(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)4011 void AssemblerARM32::vshlqi(Type ElmtTy, const Operand *OpQd,
4012 const Operand *OpQm, const Operand *OpQn) {
4013 // VSHL - ARM section A8.8.396, encoding A1:
4014 // vshl Qd, Qm, Qn
4015 //
4016 // 1111001U0Dssnnnndddd0100NQM0mmmm where Ddddd=Qd, Mmmmm=Qm, Nnnnn=Qn, 0=U,
4017 // 1=Q
4018 assert(isScalarIntegerType(ElmtTy) &&
4019 "vshl expects vector with integer element type");
4020 constexpr const char *Vshl = "vshl";
4021 constexpr IValueT VshlOpcode = B10 | B6;
4022 emitSIMDqqq(VshlOpcode, ElmtTy, OpQd, OpQn, OpQm, Vshl);
4023 }
4024
vshlqc(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const ConstantInteger32 * Imm6)4025 void AssemblerARM32::vshlqc(Type ElmtTy, const Operand *OpQd,
4026 const Operand *OpQm,
4027 const ConstantInteger32 *Imm6) {
4028 // VSHL - ARM section A8.8.395, encoding A1:
4029 // vshl Qd, Qm, #Imm
4030 //
4031 // 1111001U1Diiiiiidddd0101LQM1mmmm where Ddddd=Qd, Mmmmm=Qm, iiiiii=Imm6,
4032 // 0=U, 1=Q, 0=L.
4033 assert(isScalarIntegerType(ElmtTy) &&
4034 "vshl expects vector with integer element type");
4035 constexpr const char *Vshl = "vshl";
4036 constexpr IValueT VshlOpcode = B23 | B10 | B8 | B4;
4037 emitSIMDShiftqqc(VshlOpcode, OpQd, OpQm,
4038 encodeSIMDShiftImm6(ST_Vshl, ElmtTy, Imm6), Vshl);
4039 }
4040
vshrqc(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const ConstantInteger32 * Imm6,InstARM32::FPSign Sign)4041 void AssemblerARM32::vshrqc(Type ElmtTy, const Operand *OpQd,
4042 const Operand *OpQm, const ConstantInteger32 *Imm6,
4043 InstARM32::FPSign Sign) {
4044 // VSHR - ARM section A8.8.398, encoding A1:
4045 // vshr Qd, Qm, #Imm
4046 //
4047 // 1111001U1Diiiiiidddd0101LQM1mmmm where Ddddd=Qd, Mmmmm=Qm, iiiiii=Imm6,
4048 // U=Unsigned, Q=1, L=0.
4049 assert(isScalarIntegerType(ElmtTy) &&
4050 "vshr expects vector with integer element type");
4051 constexpr const char *Vshr = "vshr";
4052 const IValueT VshrOpcode =
4053 (Sign == InstARM32::FS_Unsigned ? B24 : 0) | B23 | B4;
4054 emitSIMDShiftqqc(VshrOpcode, OpQd, OpQm,
4055 encodeSIMDShiftImm6(ST_Vshr, ElmtTy, Imm6), Vshr);
4056 }
4057
vshlqu(Type ElmtTy,const Operand * OpQd,const Operand * OpQm,const Operand * OpQn)4058 void AssemblerARM32::vshlqu(Type ElmtTy, const Operand *OpQd,
4059 const Operand *OpQm, const Operand *OpQn) {
4060 // VSHL - ARM section A8.8.396, encoding A1:
4061 // vshl Qd, Qm, Qn
4062 //
4063 // 1111001U0Dssnnnndddd0100NQM0mmmm where Ddddd=Qd, Mmmmm=Qm, Nnnnn=Qn, 1=U,
4064 // 1=Q
4065 assert(isScalarIntegerType(ElmtTy) &&
4066 "vshl expects vector with integer element type");
4067 constexpr const char *Vshl = "vshl";
4068 constexpr IValueT VshlOpcode = B24 | B10 | B6;
4069 emitSIMDqqq(VshlOpcode, ElmtTy, OpQd, OpQn, OpQm, Vshl);
4070 }
4071
vsqrtd(const Operand * OpDd,const Operand * OpDm,CondARM32::Cond Cond)4072 void AssemblerARM32::vsqrtd(const Operand *OpDd, const Operand *OpDm,
4073 CondARM32::Cond Cond) {
4074 // VSQRT - ARM section A8.8.401, encoding A1:
4075 // vsqrt<c>.f64 <Dd>, <Dm>
4076 //
4077 // cccc11101D110001dddd101111M0mmmm where cccc=Cond, Ddddd=Sd, and Mmmmm=Sm.
4078 constexpr const char *Vsqrtd = "vsqrtd";
4079 IValueT Dd = encodeDRegister(OpDd, "Dd", Vsqrtd);
4080 IValueT Dm = encodeDRegister(OpDm, "Dm", Vsqrtd);
4081 constexpr IValueT VsqrtdOpcode = B23 | B21 | B20 | B16 | B7 | B6;
4082 constexpr IValueT D0 = 0;
4083 emitVFPddd(Cond, VsqrtdOpcode, Dd, D0, Dm);
4084 }
4085
vsqrts(const Operand * OpSd,const Operand * OpSm,CondARM32::Cond Cond)4086 void AssemblerARM32::vsqrts(const Operand *OpSd, const Operand *OpSm,
4087 CondARM32::Cond Cond) {
4088 // VSQRT - ARM section A8.8.401, encoding A1:
4089 // vsqrt<c>.f32 <Sd>, <Sm>
4090 //
4091 // cccc11101D110001dddd101011M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
4092 constexpr const char *Vsqrts = "vsqrts";
4093 IValueT Sd = encodeSRegister(OpSd, "Sd", Vsqrts);
4094 IValueT Sm = encodeSRegister(OpSm, "Sm", Vsqrts);
4095 constexpr IValueT VsqrtsOpcode = B23 | B21 | B20 | B16 | B7 | B6;
4096 constexpr IValueT S0 = 0;
4097 emitVFPsss(Cond, VsqrtsOpcode, Sd, S0, Sm);
4098 }
4099
4100 } // end of namespace ARM32
4101 } // end of namespace Ice
4102