1 //===- subzero/src/IceAssemblerARM32.h - 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 Declares the Assembler class for ARM32.
20 ///
21 /// Note: All references to ARM "section" documentation refers to the "ARM
22 /// Architecture Reference Manual, ARMv7-A and ARMv7-R edition". See:
23 /// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c
24 ///
25 //===----------------------------------------------------------------------===//
26 
27 #ifndef SUBZERO_SRC_ICEASSEMBLERARM32_H
28 #define SUBZERO_SRC_ICEASSEMBLERARM32_H
29 
30 #include "IceAssembler.h"
31 #include "IceConditionCodesARM32.h"
32 #include "IceDefs.h"
33 #include "IceFixups.h"
34 #include "IceInstARM32.h"
35 #include "IceRegistersARM32.h"
36 #include "IceTargetLowering.h"
37 
38 namespace Ice {
39 namespace ARM32 {
40 
41 /// Handles encoding of bottom/top 16 bits of an address using movw/movt.
42 class MoveRelocatableFixup final : public AssemblerFixup {
43   MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete;
44   MoveRelocatableFixup(const MoveRelocatableFixup &) = default;
45 
46 public:
47   MoveRelocatableFixup() = default;
48   size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
49   void emitOffset(Assembler *Asm) const;
50 };
51 
52 /// Handles encoding of branch and link to global location.
53 class BlRelocatableFixup final : public AssemblerFixup {
54   BlRelocatableFixup(const BlRelocatableFixup &) = delete;
55   BlRelocatableFixup &operator=(const BlRelocatableFixup &) = delete;
56 
57 public:
58   BlRelocatableFixup() = default;
59   size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
60   void emitOffset(Assembler *Asm) const;
61 };
62 
63 class AssemblerARM32 : public Assembler {
64   AssemblerARM32(const AssemblerARM32 &) = delete;
65   AssemblerARM32 &operator=(const AssemblerARM32 &) = delete;
66 
67 public:
68   // Rotation values.
69   enum RotationValue {
70     kRotateNone, // Omitted
71     kRotate8,    // ror #8
72     kRotate16,   // ror #16
73     kRotate24    // ror #24
74   };
75 
76   // Encoding of the number of D registers in a list of D registers.
77   enum DRegListSize {
78     DRegListSize1 = 7,  // 0b0111
79     DRegListSize2 = 10, // 0b1010
80     DRegListSIze3 = 6,  // 0b0110
81     DRegListSize4 = 2   // 0b0010
82   };
83 
84   class TargetInfo {
85     TargetInfo(const TargetInfo &) = delete;
86     TargetInfo &operator=(const TargetInfo &) = delete;
87 
88   public:
TargetInfo(bool HasFramePointer,RegNumT FrameOrStackReg)89     TargetInfo(bool HasFramePointer, RegNumT FrameOrStackReg)
90         : HasFramePointer(HasFramePointer), FrameOrStackReg(FrameOrStackReg) {}
TargetInfo(const TargetLowering * Target)91     explicit TargetInfo(const TargetLowering *Target)
92         : HasFramePointer(Target->hasFramePointer()),
93           FrameOrStackReg(Target->getFrameOrStackReg()) {}
94     const bool HasFramePointer;
95     const RegNumT FrameOrStackReg;
96   };
97 
98   explicit AssemblerARM32(bool IsNonsfi, bool use_far_branches = false)
Assembler(Asm_ARM32)99       : Assembler(Asm_ARM32), IsNonsfi(IsNonsfi) {
100     // TODO(kschimpf): Add mode if needed when branches are handled.
101     (void)use_far_branches;
102   }
~AssemblerARM32()103   ~AssemblerARM32() override {
104     if (BuildDefs::asserts()) {
105       for (const Label *Label : CfgNodeLabels) {
106         Label->finalCheck();
107       }
108       for (const Label *Label : LocalLabels) {
109         Label->finalCheck();
110       }
111     }
112   }
113 
114   MoveRelocatableFixup *createMoveFixup(bool IsMovW, const Constant *Value);
115 
116   BlRelocatableFixup *createBlFixup(const ConstantRelocatable *BlTarget);
117 
alignFunction()118   void alignFunction() override {
119     const SizeT Align = 1 << getBundleAlignLog2Bytes();
120     SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align);
121     constexpr SizeT InstSize = sizeof(IValueT);
122     assert(BytesNeeded % InstARM32::InstSize == 0);
123     while (BytesNeeded > 0) {
124       trap();
125       BytesNeeded -= InstSize;
126     }
127   }
128 
getBundleAlignLog2Bytes()129   SizeT getBundleAlignLog2Bytes() const override { return 4; }
130 
getAlignDirective()131   const char *getAlignDirective() const override { return ".p2alignl"; }
132 
133   llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const override;
134 
135   void padWithNop(intptr_t Padding) override;
136 
getCfgNodeLabel(SizeT NodeNumber)137   Ice::Label *getCfgNodeLabel(SizeT NodeNumber) override {
138     assert(NodeNumber < CfgNodeLabels.size());
139     return CfgNodeLabels[NodeNumber];
140   }
141 
getOrCreateCfgNodeLabel(SizeT NodeNumber)142   Label *getOrCreateCfgNodeLabel(SizeT NodeNumber) {
143     return getOrCreateLabel(NodeNumber, CfgNodeLabels);
144   }
145 
getOrCreateLocalLabel(SizeT Number)146   Label *getOrCreateLocalLabel(SizeT Number) {
147     return getOrCreateLabel(Number, LocalLabels);
148   }
149 
bindLocalLabel(const InstARM32Label * InstL,SizeT Number)150   void bindLocalLabel(const InstARM32Label *InstL, SizeT Number) {
151     if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) {
152       constexpr SizeT InstSize = 0;
153       emitTextInst(InstL->getLabelName() + ":", InstSize);
154     }
155     Label *L = getOrCreateLocalLabel(Number);
156     if (!getPreliminary())
157       this->bind(L);
158   }
159 
fixupIsPCRel(FixupKind Kind)160   bool fixupIsPCRel(FixupKind Kind) const override {
161     if (Kind == llvm::ELF::R_ARM_MOVW_PREL_NC)
162       return true;
163     if (Kind == llvm::ELF::R_ARM_MOVT_PREL)
164       return true;
165     return false;
166   }
167 
168   /// Accessors to keep track of the number of bytes generated inside
169   /// InstARM32::emit() methods, when run inside of
170   /// InstARM32::emitUsingTextFixup().
resetEmitTextSize()171   void resetEmitTextSize() { EmitTextSize = 0; }
incEmitTextSize(size_t Amount)172   void incEmitTextSize(size_t Amount) { EmitTextSize += Amount; }
decEmitTextSize(size_t Amount)173   void decEmitTextSize(size_t Amount) { EmitTextSize -= Amount; }
getEmitTextSize()174   size_t getEmitTextSize() const { return EmitTextSize; }
175 
176   void bind(Label *label);
177 
178   // List of instructions implemented by integrated assembler.
179 
180   void adc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
181            bool SetFlags, CondARM32::Cond Cond);
182 
183   void add(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
184            bool SetFlags, CondARM32::Cond Cond);
185 
186   void and_(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
187             bool SetFlags, CondARM32::Cond Cond);
188 
189   void asr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
190            bool SetFlags, CondARM32::Cond Cond);
191 
192   void b(Label *L, CondARM32::Cond Cond);
193 
194   void bkpt(uint16_t Imm16);
195 
196   void bic(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
197            bool SetFlags, CondARM32::Cond Cond);
198 
199   void bl(const ConstantRelocatable *Target);
200 
201   void blx(const Operand *Target);
202 
203   void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
204 
205   void clz(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
206 
207   void cmn(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond);
208 
209   void cmp(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond);
210 
211   void dmb(IValueT Option); // Option is a 4-bit value.
212 
213   void eor(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
214            bool SetFlags, CondARM32::Cond Cond);
215 
216   void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
217            const TargetInfo &TInfo);
218 
ldr(const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)219   void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
220            const TargetLowering *Lowering) {
221     const TargetInfo TInfo(Lowering);
222     ldr(OpRt, OpAddress, Cond, TInfo);
223   }
224 
225   void ldrex(const Operand *OpRt, const Operand *OpAddress,
226              CondARM32::Cond Cond, const TargetInfo &TInfo);
227 
ldrex(const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)228   void ldrex(const Operand *OpRt, const Operand *OpAddress,
229              CondARM32::Cond Cond, const TargetLowering *Lowering) {
230     const TargetInfo TInfo(Lowering);
231     ldrex(OpRt, OpAddress, Cond, TInfo);
232   }
233 
234   void lsl(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
235            bool SetFlags, CondARM32::Cond Cond);
236 
237   void lsr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
238            bool SetFlags, CondARM32::Cond Cond);
239 
240   void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
241 
242   void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
243 
244   void movt(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
245 
246   void mla(const Operand *OpRd, const Operand *OpRn, const Operand *OpRm,
247            const Operand *OpRa, CondARM32::Cond Cond);
248 
249   void mls(const Operand *OpRd, const Operand *OpRn, const Operand *OpRm,
250            const Operand *OpRa, CondARM32::Cond Cond);
251 
252   void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
253            bool SetFlags, CondARM32::Cond Cond);
254 
255   void mvn(const Operand *OpRd, const Operand *OpScc, CondARM32::Cond Cond);
256 
257   void nop();
258 
259   void orr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
260            bool SetFlags, CondARM32::Cond Cond);
261 
262   void pop(const Variable *OpRt, CondARM32::Cond Cond);
263 
264   // Note: Registers is a bitset, where bit n corresponds to register Rn.
265   void popList(const IValueT Registers, CondARM32::Cond Cond);
266 
267   void push(const Operand *OpRt, CondARM32::Cond Cond);
268 
269   // Note: Registers is a bitset, where bit n corresponds to register Rn.
270   void pushList(const IValueT Registers, CondARM32::Cond Cond);
271 
272   void rbit(const Operand *OpRd, const Operand *OpRm, CondARM32::Cond Cond);
273 
274   void rev(const Operand *OpRd, const Operand *OpRm, CondARM32::Cond Cond);
275 
276   void rsb(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
277            bool SetFlags, CondARM32::Cond Cond);
278 
279   void rsc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
280            bool SetFlags, CondARM32::Cond Cond);
281 
282   void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
283            bool SetFlags, CondARM32::Cond Cond);
284 
285   void sdiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
286             CondARM32::Cond Cond);
287 
288   void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
289            const TargetInfo &TInfo);
290 
str(const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)291   void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
292            const TargetLowering *Lowering) {
293     const TargetInfo TInfo(Lowering);
294     str(OpRt, OpAddress, Cond, TInfo);
295   }
296 
297   void strex(const Operand *OpRd, const Operand *OpRt, const Operand *OpAddress,
298              CondARM32::Cond Cond, const TargetInfo &TInfo);
299 
strex(const Operand * OpRd,const Operand * OpRt,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)300   void strex(const Operand *OpRd, const Operand *OpRt, const Operand *OpAddress,
301              CondARM32::Cond Cond, const TargetLowering *Lowering) {
302     const TargetInfo TInfo(Lowering);
303     strex(OpRd, OpRt, OpAddress, Cond, TInfo);
304   }
305 
306   void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
307            bool SetFlags, CondARM32::Cond Cond);
308 
309   // Implements sxtb/sxth depending on type of OpSrc0.
310   void sxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond);
311 
312   void trap();
313 
314   void tst(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond);
315 
316   void udiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
317             CondARM32::Cond Cond);
318 
319   void umull(const Operand *OpRdLo, const Operand *OpRdHi, const Operand *OpRn,
320              const Operand *OpRm, CondARM32::Cond Cond);
321 
322   // Implements uxtb/uxth depending on type of OpSrc0.
323   void uxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond);
324 
325   void vabss(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond);
326 
327   void vabsd(const Operand *OpDd, const Operand *OpDm, CondARM32::Cond Cond);
328 
329   void vabsq(const Operand *OpQd, const Operand *OpQm);
330 
331   void vaddd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
332              CondARM32::Cond Cond);
333 
334   void vadds(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
335              CondARM32::Cond Cond);
336 
337   // Integer vector add.
338   void vaddqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
339               const Operand *OpQn);
340 
341   // Float vector add.
342   void vaddqf(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
343 
344   void vandq(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
345 
346   void vbslq(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
347 
348   void vceqqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
349               const Operand *OpQn);
350 
351   void vceqqs(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
352 
353   void vcgeqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
354               const Operand *OpQn);
355 
356   void vcugeqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
357                const Operand *OpQn);
358 
359   void vcgeqs(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
360 
361   void vcgtqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
362               const Operand *OpQn);
363 
364   void vcugtqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
365                const Operand *OpQn);
366 
367   void vcgtqs(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
368 
369   void vcmpd(const Operand *OpDd, const Operand *OpDm, CondARM32::Cond cond);
370 
371   // Second argument of compare is zero (+0.0).
372   void vcmpdz(const Operand *OpDd, CondARM32::Cond cond);
373 
374   void vcmps(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond cond);
375 
376   // Second argument of compare is zero (+0.0).
377   void vcmpsz(const Operand *OpSd, CondARM32::Cond cond);
378 
379   void vcvtds(const Operand *OpDd, const Operand *OpSm, CondARM32::Cond Cond);
380 
381   // vcvt<c>.S32.F32
382   void vcvtis(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond);
383 
384   // vcvt<c>.S32.F64
385   void vcvtid(const Operand *OpSd, const Operand *OpDm, CondARM32::Cond Cond);
386 
387   // vcvt<c>.F64.S32
388   void vcvtdi(const Operand *OpDd, const Operand *OpSm, CondARM32::Cond Cond);
389 
390   // vcvt<c>.F64.U32
391   void vcvtdu(const Operand *OpDd, const Operand *OpSm, CondARM32::Cond Cond);
392 
393   void vcvtsd(const Operand *OpSd, const Operand *OpDm, CondARM32::Cond Cond);
394 
395   // vcvt<c>.F32.S32
396   void vcvtsi(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond);
397 
398   // vcvt<c>.F32.U32
399   void vcvtsu(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond);
400 
401   // vcvt<c>.U32.F64
402   void vcvtud(const Operand *OpSd, const Operand *OpDm, CondARM32::Cond Cond);
403 
404   // vcvt<c>.u32.f32
405   void vcvtus(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond);
406 
407   void vcvtqsi(const Operand *OpQd, const Operand *OpQm);
408 
409   void vcvtqsu(const Operand *OpQd, const Operand *OpQm);
410 
411   void vcvtqis(const Operand *OpQd, const Operand *OpQm);
412 
413   void vcvtqus(const Operand *OpQd, const Operand *OpQm);
414 
415   void vdivd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
416              CondARM32::Cond Cond);
417 
418   void vdivs(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
419              CondARM32::Cond Cond);
420 
421   void veord(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm);
422 
423   void veorq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
424 
425   void vldrd(const Operand *OpDd, const Operand *OpAddress,
426              CondARM32::Cond Cond, const TargetInfo &TInfo);
427 
vldrd(const Operand * OpDd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)428   void vldrd(const Operand *OpDd, const Operand *OpAddress,
429              CondARM32::Cond Cond, const TargetLowering *Lowering) {
430     const TargetInfo TInfo(Lowering);
431     vldrd(OpDd, OpAddress, Cond, TInfo);
432   }
433 
434   void vldrs(const Operand *OpSd, const Operand *OpAddress,
435              CondARM32::Cond Cond, const TargetInfo &TInfo);
436 
vldrs(const Operand * OpSd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)437   void vldrs(const Operand *OpSd, const Operand *OpAddress,
438              CondARM32::Cond Cond, const TargetLowering *Lowering) {
439     const TargetInfo TInfo(Lowering);
440     vldrs(OpSd, OpAddress, Cond, TInfo);
441   }
442 
443   void vldrq(const Operand *OpQd, const Operand *OpAddress,
444              CondARM32::Cond Cond, const TargetInfo &TInfo);
445 
vldrq(const Operand * OpQd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)446   void vldrq(const Operand *OpQd, const Operand *OpAddress,
447              CondARM32::Cond Cond, const TargetLowering *Lowering) {
448     const TargetInfo TInfo(Lowering);
449     vldrq(OpQd, OpAddress, Cond, TInfo);
450   }
451 
452   // ElmtSize = #bits in vector element.
453   void vld1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
454               const TargetInfo &TInfo);
455 
456   void vld1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
457             const TargetInfo &TInfo);
458 
vld1qr(size_t ElmtSize,const Operand * OpQd,const Operand * OpRn,const TargetLowering * Lowering)459   void vld1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
460               const TargetLowering *Lowering) {
461     const TargetInfo TInfo(Lowering);
462     vld1qr(ElmtSize, OpQd, OpRn, TInfo);
463   }
464 
vld1(size_t ElmtSize,const Operand * OpQd,const Operand * OpRn,const TargetLowering * Lowering)465   void vld1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
466             const TargetLowering *Lowering) {
467     const TargetInfo TInfo(Lowering);
468     vld1(ElmtSize, OpQd, OpRn, TInfo);
469   }
470 
471   // Qn[i] = Imm for all i in vector. Returns true iff Imm can be defined as an
472   // Imm8 using AdvSIMDExpandImm().
473   bool vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm);
474 
475   // Dn = FpImm
476   void vmovd(const Operand *OpDn, const OperandARM32FlexFpImm *OpFpImm,
477              CondARM32::Cond Cond);
478 
479   // Dd = Dm
480   void vmovdd(const Operand *OpDd, const Variable *OpDm, CondARM32::Cond Cond);
481 
482   // Dm = Rt:Rt2
483   void vmovdrr(const Operand *OpDm, const Operand *OpRt, const Operand *OpRt2,
484                CondARM32::Cond Cond);
485 
486   // Qd[Index] = Rt
487   void vmovqir(const Operand *OpQd, uint32_t Index, const Operand *OpRt,
488                CondARM32::Cond Cond);
489 
490   // Qd[Index] = Sm
491   void vmovqis(const Operand *OpQd, uint32_t Indx, const Operand *OpSm,
492                CondARM32::Cond Cond);
493 
494   // Rt = Qm[Index]
495   void vmovrqi(const Operand *OpRt, const Operand *OpQd, uint32_t Index,
496                CondARM32::Cond Cond);
497 
498   // Rt:Rt2 = Dm
499   void vmovrrd(const Operand *OpRt, const Operand *OpRt2, const Operand *OpDm,
500                CondARM32::Cond Cond);
501 
502   // Rt = Sn
503   void vmovrs(const Operand *OpRt, const Operand *OpSn, CondARM32::Cond Cond);
504 
505   // Sn = FpImm
506   void vmovs(const Operand *OpSn, const OperandARM32FlexFpImm *OpFpImm,
507              CondARM32::Cond Cond);
508 
509   // Sd = Sm
510   void vmovss(const Operand *OpSd, const Variable *OpSm, CondARM32::Cond Cond);
511 
512   // Sd = Qm[Index]
513   void vmovsqi(const Operand *OpSd, const Operand *OpQm, uint32_t Index,
514                CondARM32::Cond Cond);
515 
516   // Sn = Rt
517   void vmovsr(const Operand *OpSn, const Operand *OpRt, CondARM32::Cond Cond);
518 
519   void vmlad(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
520              CondARM32::Cond Cond);
521 
522   void vmlas(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
523              CondARM32::Cond Cond);
524 
525   void vmlsd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
526              CondARM32::Cond Cond);
527 
528   void vmlss(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
529              CondARM32::Cond Cond);
530 
531   // Uses APSR_nzcv as register
532   void vmrsAPSR_nzcv(CondARM32::Cond Cond);
533 
534   void vmuld(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
535              CondARM32::Cond Cond);
536 
537   // Integer vector multiply.
538   void vmulqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
539               const Operand *OpQm);
540 
541   // Integer vector multiply high.
542   void vmulh(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
543              const Operand *OpQm, bool Unsigned);
544 
545   // Integer vector multiply add pairwise.
546   void vmlap(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
547              const Operand *OpQm);
548 
549   // Vector element replication.
550   void vdup(Type ElmtTy, const Operand *OpQd, const Operand *OpQn, IValueT Idx);
551 
552   // Vector interleave lower halves.
553   void vzip(Type ElmtTy, const Operand *OpQd, const Operand *OpQn,
554             const Operand *OpQm);
555 
556   // Float vector multiply.
557   void vmulqf(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
558 
559   void vmuls(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
560              CondARM32::Cond Cond);
561 
562   void vmvnq(const Operand *OpQd, const Operand *OpQm);
563 
564   void vmovlq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
565   void vmovhq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
566   void vmovhlq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
567   void vmovlhq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm);
568 
569   void vnegqs(const Operand *OpQd, const Operand *OpQm);
570 
571   void vnegqs(Type ElmtTy, const Operand *OpQd, const Operand *OpQm);
572 
573   void vorrq(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
574 
575   void vpop(const Variable *OpBaseReg, SizeT NumConsecRegs,
576             CondARM32::Cond Cond);
577 
578   void vpush(const Variable *OpBaseReg, SizeT NumConsecRegs,
579              CondARM32::Cond Cond);
580 
581   void vshlqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
582               const Operand *OpQn);
583 
584   void vshlqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
585               const Operand *OpQn);
586 
587   void vshlqc(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
588               const ConstantInteger32 *OpQn);
589 
590   void vshrqc(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
591               const ConstantInteger32 *OpQn, InstARM32::FPSign Sign);
592 
593   void vsqrtd(const Operand *OpDd, const Operand *OpDm, CondARM32::Cond Cond);
594 
595   void vsqrts(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond);
596 
597   void vstrd(const Operand *OpDd, const Operand *OpAddress,
598              CondARM32::Cond Cond, const TargetInfo &TInfo);
599 
vstrd(const Operand * OpDd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)600   void vstrd(const Operand *OpDd, const Operand *OpAddress,
601              CondARM32::Cond Cond, const TargetLowering *Lowering) {
602     const TargetInfo TInfo(Lowering);
603     vstrd(OpDd, OpAddress, Cond, TInfo);
604   }
605 
606   void vstrs(const Operand *OpSd, const Operand *OpAddress,
607              CondARM32::Cond Cond, const TargetInfo &TInfo);
608 
vstrs(const Operand * OpSd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)609   void vstrs(const Operand *OpSd, const Operand *OpAddress,
610              CondARM32::Cond Cond, const TargetLowering *Lowering) {
611     const TargetInfo TInfo(Lowering);
612     vstrs(OpSd, OpAddress, Cond, TInfo);
613   }
614 
615   void vstrq(const Operand *OpQd, const Operand *OpAddress,
616              CondARM32::Cond Cond, const TargetInfo &TInfo);
617 
vstrq(const Operand * OpQd,const Operand * OpAddress,CondARM32::Cond Cond,const TargetLowering * Lowering)618   void vstrq(const Operand *OpQd, const Operand *OpAddress,
619              CondARM32::Cond Cond, const TargetLowering *Lowering) {
620     const TargetInfo TInfo(Lowering);
621     vstrq(OpQd, OpAddress, Cond, TInfo);
622   }
623 
624   // ElmtSize = #bits in vector element.
625   void vst1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpAddress,
626               const TargetInfo &TInfo);
627 
vst1qr(size_t ElmtSize,const Operand * OpQd,const Operand * OpRn,const TargetLowering * Lowering)628   void vst1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
629               const TargetLowering *Lowering) {
630     const TargetInfo TInfo(Lowering);
631     vst1qr(ElmtSize, OpQd, OpRn, TInfo);
632   }
633 
634   void vst1(size_t ElmtSize, const Operand *OpQd, const Operand *OpAddress,
635             const TargetInfo &TInfo);
636 
vst1(size_t ElmtSize,const Operand * OpQd,const Operand * OpRn,const TargetLowering * Lowering)637   void vst1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn,
638             const TargetLowering *Lowering) {
639     const TargetInfo TInfo(Lowering);
640     vst1(ElmtSize, OpQd, OpRn, TInfo);
641   }
642 
643   void vsubd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
644              CondARM32::Cond Cond);
645 
646   // Integer vector subtract.
647   void vsubqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
648               const Operand *OpQn);
649 
650   // Integer vector saturating subtract.
651   void vqsubqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
652                const Operand *OpQn);
653   void vqsubqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
654                const Operand *OpQn);
655 
656   // Integer vector saturating add.
657   void vqaddqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
658                const Operand *OpQn);
659   void vqaddqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
660                const Operand *OpQn);
661 
662   // Integer vector packing with optional saturation.
663   void vqmovn2(Type ElmtTy, const Operand *OpQd, const Operand *OpQm,
664                const Operand *OpQn, bool Unsigned, bool Saturating);
665 
666   // Float vector subtract
667   void vsubqf(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn);
668 
669   void vsubs(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
670              CondARM32::Cond Cond);
671 
classof(const Assembler * Asm)672   static bool classof(const Assembler *Asm) {
673     return Asm->getKind() == Asm_ARM32;
674   }
675 
676   void emitTextInst(const std::string &Text, SizeT InstSize);
677 
678 private:
679   ENABLE_MAKE_UNIQUE;
680 
681   const bool IsNonsfi;
682 
683   // A vector of pool-allocated x86 labels for CFG nodes.
684   using LabelVector = std::vector<Label *>;
685   LabelVector CfgNodeLabels;
686   // A vector of pool-allocated x86 labels for Local labels.
687   LabelVector LocalLabels;
688   // Number of bytes emitted by InstARM32::emit() methods, when run inside
689   // InstARM32::emitUsingTextFixup().
690   size_t EmitTextSize = 0;
691 
692   // Load/store multiple addressing mode.
693   enum BlockAddressMode {
694     // bit encoding P U W
695     DA = (0 | 0 | 0) << 21,   // decrement after
696     IA = (0 | 4 | 0) << 21,   // increment after
697     DB = (8 | 0 | 0) << 21,   // decrement before
698     IB = (8 | 4 | 0) << 21,   // increment before
699     DA_W = (0 | 0 | 1) << 21, // decrement after with writeback to base
700     IA_W = (0 | 4 | 1) << 21, // increment after with writeback to base
701     DB_W = (8 | 0 | 1) << 21, // decrement before with writeback to base
702     IB_W = (8 | 4 | 1) << 21  // increment before with writeback to base
703   };
704 
705   Label *getOrCreateLabel(SizeT Number, LabelVector &Labels);
706 
707   void bindCfgNodeLabel(const CfgNode *Node) override;
708 
709   // SIMD encoding for the vector ElmtTy.
710   static IValueT encodeElmtType(Type ElmtTy);
711 
emitInst(IValueT Value)712   void emitInst(IValueT Value) {
713     AssemblerBuffer::EnsureCapacity _(&Buffer);
714     Buffer.emit<IValueT>(Value);
715   }
716 
717   // List of possible checks to apply when calling emitType01() (below).
718   enum EmitChecks { NoChecks, RdIsPcAndSetFlags };
719 
720   // Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=InstType,
721   // s=SetFlags, oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM
722   // section A5.2.3).
723   void emitType01(CondARM32::Cond Cond, IValueT InstType, IValueT Opcode,
724                   bool SetFlags, IValueT Rn, IValueT Rd, IValueT imm12,
725                   EmitChecks RuleChecks, const char *InstName);
726 
727   // Converts appropriate representation on a data operation, and then calls
728   // emitType01 above.
729   void emitType01(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRd,
730                   const Operand *OpRn, const Operand *OpSrc1, bool SetFlags,
731                   EmitChecks RuleChecks, const char *InstName);
732 
733   // Same as above, but the value for Rd and Rn have already been converted
734   // into instruction values.
735   void emitType01(CondARM32::Cond Cond, IValueT Opcode, IValueT OpRd,
736                   IValueT OpRn, const Operand *OpSrc1, bool SetFlags,
737                   EmitChecks RuleChecks, const char *InstName);
738 
739   void emitType05(CondARM32::Cond Cond, int32_t Offset, bool Link);
740 
741   // Emit ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond,
742   // ooo=InstType, l=isLoad, b=isByte, and
743   // aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that Address is assumed to be
744   // defined by decodeAddress() in IceAssemblerARM32.cpp.
745   void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad,
746                  bool IsByte, IValueT Rt, IValueT Address);
747 
748   // Emit ccccxxxxxxxxxxxxddddxxxxxxxxmmmm where cccc=Cond,
749   // xxxxxxxxxxxx0000xxxxxxxx0000=Opcode, dddd=Rd, and mmmm=Rm.
750   void emitRdRm(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRd,
751                 const Operand *OpRm, const char *InstName);
752 
753   // Emit ldr/ldrb/str/strb instruction with given address.
754   void emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, IValueT Rt,
755                  const Operand *OpAddress, const TargetInfo &TInfo,
756                  const char *InstName);
757 
758   // Emit ldrh/ldrd/strh/strd instruction with given address using encoding 3.
759   void emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, IValueT Rt,
760                      const Operand *OpAddress, const TargetInfo &TInfo,
761                      const char *InstName);
762 
763   // Emit cccc00011xxlnnnndddd11111001tttt where cccc=Cond, xx encodes type
764   // size, l=IsLoad, nnnn=Rn (as defined by OpAddress), and tttt=Rt.
765   void emitMemExOp(CondARM32::Cond, Type Ty, bool IsLoad, const Operand *OpRd,
766                    IValueT Rt, const Operand *OpAddress,
767                    const TargetInfo &TInfo, const char *InstName);
768 
769   // Pattern cccc100aaaalnnnnrrrrrrrrrrrrrrrr where cccc=Cond,
770   // aaaa<<21=AddressMode, l=IsLoad, nnnn=BaseReg, and
771   // rrrrrrrrrrrrrrrr is bitset of Registers.
772   void emitMultiMemOp(CondARM32::Cond Cond, BlockAddressMode AddressMode,
773                       bool IsLoad, IValueT BaseReg, IValueT Registers);
774 
775   // Pattern ccccxxxxxDxxxxxxddddxxxxiiiiiiii where cccc=Cond, ddddD=BaseReg,
776   // iiiiiiii=NumConsecRegs, and xxxxx0xxxxxx0000xxxx00000000=Opcode.
777   void emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
778                     const Variable *OpBaseReg, SizeT NumConsecRegs);
779 
780   // Pattern cccc111xxDxxxxxxdddd101xxxMxmmmm where cccc=Cond, ddddD=Sd,
781   // Mmmmm=Dm, and xx0xxxxxxdddd000xxx0x0000=Opcode.
782   void emitVFPsd(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd, IValueT Dm);
783 
784   // Pattern cccc111xxDxxxxxxdddd101xxxMxmmmm where cccc=Cond, Ddddd=Dd,
785   // mmmmM=Sm, and xx0xxxxxxdddd000xxx0x0000=Opcode.
786   void emitVFPds(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, IValueT Sm);
787 
788   // Pattern 111100000D00nnnnddddttttssaammmm | Opcode where Ddddd=Dd, nnnn=Rn,
789   // mmmmm=Rm, tttt=NumDRegs, ElmtSize in {8, 16, 32, 64) and defines ss, and
790   // aa=Align.
791   void emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn, IValueT Rm,
792                    DRegListSize NumDRegs, size_t ElmtSize, IValueT Align,
793                    const char *InstName);
794 
795   // Pattern 111100000D00nnnnddddss00aaaammmm | Opcode where Ddddd=Dd, nnnn=Rn,
796   // mmmmm=Rm, ElmtSize in {8, 16, 32) and defines ss, and aa=Align.
797   void emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn, IValueT Rm,
798                    size_t ElmtSize, IValueT Align, const char *InstName);
799 
800   // Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond,
801   // x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm.
802   void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
803                  IValueT Rm);
804 
805   // cccc1110iiiennnntttt1011Njj10000 where cccc=Cond, tttt=Rt, Ndddd=2*Qn=Dn,
806   // iii=Opcode1, jj=Opcode2, Opcode1Opcode2 encodes Index and the
807   // corresponding element size of the vector element, and e=IsExtract.
808   void emitInsertExtractInt(CondARM32::Cond Cond, const Operand *OpQn,
809                             uint32_t Index, const Operand *OpRt, bool IsExtract,
810                             const char *InstName);
811 
812   // cccc11101D110000dddd101001M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm.
813   // Assigns Sd the value of Sm.
814   void emitMoveSS(CondARM32::Cond Cond, IValueT Sd, IValueT Sm);
815 
816   // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
817   // mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode.
818   void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
819                  IValueT Rm, IValueT Rs, bool SetFlags);
820 
821   // Pattern cccc0001101s0000ddddxxxxxtt0mmmm where cccc=Cond, s=SetFlags,
822   // dddd=Rd, mmmm=Rm, tt=Shift, and xxxxx is defined by OpSrc1. OpSrc1 defines
823   // either xxxxx=Imm5, or xxxxx=ssss0 where ssss=Rs.
824   void emitShift(const CondARM32::Cond Cond,
825                  const OperandARM32::ShiftKind Shift, const Operand *OpRd,
826                  const Operand *OpRm, const Operand *OpSrc1,
827                  const bool SetFlags, const char *InstName);
828 
829   // Implements various forms of signed/unsigned extend value, using pattern
830   // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
831   // nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm.
832   void emitSignExtend(CondARM32::Cond, IValueT Opcode, const Operand *OpRd,
833                       const Operand *OpSrc0, const char *InstName);
834 
835   // Implements various forms of vector (SIMD) operations.  Implements pattern
836   // 111100100D00nnnndddn00F0NQM0mmmm where Dddd=Dd, Nnnn=Dn, Mmmm=Dm,
837   // Q=UseQRegs, F=IsFloatTy, and Opcode is unioned into the pattern.
838   void emitSIMDBase(IValueT Opcode, IValueT Dd, IValueT Dn, IValueT Dm,
839                     bool UseQRegs, bool IsFloatTy);
840 
841   // Same as emitSIMDBase above, except ElmtShift=20 and ElmtSize is computed
842   // from ElmtTy.
843   void emitSIMD(IValueT Opcode, Type ElmtTy, IValueT Dd, IValueT Dn, IValueT Dm,
844                 bool UseQRegs);
845 
846   // Implements various integer forms of vector (SIMD) operations using Q
847   // registers. Implements pattern 111100100D00nnn0ddd000F0N1M0mmm0 where
848   // Dddd=Qd, Nnnn=Qn, Mmmm=Qm, F=IsFloatTy, and Opcode is unioned into the
849   // pattern.
850   void emitSIMDqqqBase(IValueT Opcode, const Operand *OpQd, const Operand *OpQn,
851                        const Operand *OpQm, bool IsFloatTy,
852                        const char *OpcodeName);
853 
854   // Same as emitSIMD above, except ElmtShift=20 and ElmtSize is computed from
855   // ElmtTy.
856   void emitSIMDqqq(IValueT Opcode, Type ElmtTy, const Operand *OpQd,
857                    const Operand *OpQn, const Operand *OpQm,
858                    const char *OpcodeName);
859 
860   // Implements various forms of vector (SIMD) shifts using Q registers.
861   // Implements pattern 111100101Diiiiiidddd010101M1mmmm where Dddd=Qd, Mmmm=Qm,
862   // iiiiii=Imm6, and Opcode is unioned into the pattern.
863   void emitSIMDShiftqqc(IValueT Opcode, const Operand *OpQd,
864                         const Operand *OpQm, const IValueT Imm6,
865                         const char *OpcodeName);
866 
867   // Implements various forms of vector (SIMD) casts between (signed and
868   // unsigned) integer and floating point types (f32). Implements pattern
869   // 111100111D11ss11dddd011ooQM0mmmm where Dddd=Qd, Mmmm=Qm, 10=ss, op=00, 1=Q,
870   // and Opcode is unioned into the pattern.
871   void emitSIMDCvtqq(IValueT Opcode, const Operand *OpQd, const Operand *OpQm,
872                      const char *CvtName);
873 
874   // Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn,
875   // ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from
876   // OpSrc1, and xxxx=Opcode.
877   void emitCompareOp(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRn,
878                      const Operand *OpSrc1, const char *CmpName);
879 
880   void emitBranch(Label *L, CondARM32::Cond, bool Link);
881 
882   // Returns the offset encoded in the branch instruction Inst.
883   static IOffsetT decodeBranchOffset(IValueT Inst);
884 
885   // Implements movw/movt, generating pattern ccccxxxxxxxsiiiiddddiiiiiiiiiiii
886   // where cccc=Cond, xxxxxxx<<21=Opcode, dddd=Rd, s=SetFlags, and
887   // iiiiiiiiiiiiiiii=Imm16.
888   void emitMovwt(CondARM32::Cond Cond, bool IsMovw, const Operand *OpRd,
889                  const Operand *OpSrc, const char *MovName);
890 
891   // Emit VFP instruction with 3 D registers.
892   void emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpDd,
893                   const Operand *OpDn, const Operand *OpDm,
894                   const char *InstName);
895 
896   void emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, IValueT Dn,
897                   IValueT Dm);
898 
899   // Emit VFP instruction with 3 S registers.
900   void emitVFPsss(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd, IValueT Sn,
901                   IValueT Sm);
902 
903   void emitVFPsss(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpSd,
904                   const Operand *OpSn, const Operand *OpSm,
905                   const char *InstName);
906 };
907 
908 } // end of namespace ARM32
909 } // end of namespace Ice
910 
911 #endif // SUBZERO_SRC_ICEASSEMBLERARM32_H
912