//===- subzero/src/IceAssemblerARM32.h - Assembler for ARM32 ----*- C++ -*-===// // // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. // // Modified by the Subzero authors. // //===----------------------------------------------------------------------===// // // The Subzero Code Generator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Declares the Assembler class for ARM32. /// /// Note: All references to ARM "section" documentation refers to the "ARM /// Architecture Reference Manual, ARMv7-A and ARMv7-R edition". See: /// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c /// //===----------------------------------------------------------------------===// #ifndef SUBZERO_SRC_ICEASSEMBLERARM32_H #define SUBZERO_SRC_ICEASSEMBLERARM32_H #include "IceAssembler.h" #include "IceConditionCodesARM32.h" #include "IceDefs.h" #include "IceFixups.h" #include "IceInstARM32.h" #include "IceRegistersARM32.h" #include "IceTargetLowering.h" namespace Ice { namespace ARM32 { /// Handles encoding of bottom/top 16 bits of an address using movw/movt. class MoveRelocatableFixup final : public AssemblerFixup { MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete; MoveRelocatableFixup(const MoveRelocatableFixup &) = default; public: MoveRelocatableFixup() = default; size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final; void emitOffset(Assembler *Asm) const; }; /// Handles encoding of branch and link to global location. class BlRelocatableFixup final : public AssemblerFixup { BlRelocatableFixup(const BlRelocatableFixup &) = delete; BlRelocatableFixup &operator=(const BlRelocatableFixup &) = delete; public: BlRelocatableFixup() = default; size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final; void emitOffset(Assembler *Asm) const; }; class AssemblerARM32 : public Assembler { AssemblerARM32(const AssemblerARM32 &) = delete; AssemblerARM32 &operator=(const AssemblerARM32 &) = delete; public: // Rotation values. enum RotationValue { kRotateNone, // Omitted kRotate8, // ror #8 kRotate16, // ror #16 kRotate24 // ror #24 }; // Encoding of the number of D registers in a list of D registers. enum DRegListSize { DRegListSize1 = 7, // 0b0111 DRegListSize2 = 10, // 0b1010 DRegListSIze3 = 6, // 0b0110 DRegListSize4 = 2 // 0b0010 }; class TargetInfo { TargetInfo(const TargetInfo &) = delete; TargetInfo &operator=(const TargetInfo &) = delete; public: TargetInfo(bool HasFramePointer, RegNumT FrameOrStackReg) : HasFramePointer(HasFramePointer), FrameOrStackReg(FrameOrStackReg) {} explicit TargetInfo(const TargetLowering *Target) : HasFramePointer(Target->hasFramePointer()), FrameOrStackReg(Target->getFrameOrStackReg()) {} const bool HasFramePointer; const RegNumT FrameOrStackReg; }; explicit AssemblerARM32(bool IsNonsfi, bool use_far_branches = false) : Assembler(Asm_ARM32), IsNonsfi(IsNonsfi) { // TODO(kschimpf): Add mode if needed when branches are handled. (void)use_far_branches; } ~AssemblerARM32() override { if (BuildDefs::asserts()) { for (const Label *Label : CfgNodeLabels) { Label->finalCheck(); } for (const Label *Label : LocalLabels) { Label->finalCheck(); } } } MoveRelocatableFixup *createMoveFixup(bool IsMovW, const Constant *Value); BlRelocatableFixup *createBlFixup(const ConstantRelocatable *BlTarget); void alignFunction() override { const SizeT Align = 1 << getBundleAlignLog2Bytes(); SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align); constexpr SizeT InstSize = sizeof(IValueT); assert(BytesNeeded % InstARM32::InstSize == 0); while (BytesNeeded > 0) { trap(); BytesNeeded -= InstSize; } } SizeT getBundleAlignLog2Bytes() const override { return 4; } const char *getAlignDirective() const override { return ".p2alignl"; } llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const override; void padWithNop(intptr_t Padding) override; Ice::Label *getCfgNodeLabel(SizeT NodeNumber) override { assert(NodeNumber < CfgNodeLabels.size()); return CfgNodeLabels[NodeNumber]; } Label *getOrCreateCfgNodeLabel(SizeT NodeNumber) { return getOrCreateLabel(NodeNumber, CfgNodeLabels); } Label *getOrCreateLocalLabel(SizeT Number) { return getOrCreateLabel(Number, LocalLabels); } void bindLocalLabel(const InstARM32Label *InstL, SizeT Number) { if (BuildDefs::dump() && !getFlags().getDisableHybridAssembly()) { constexpr SizeT InstSize = 0; emitTextInst(InstL->getLabelName() + ":", InstSize); } Label *L = getOrCreateLocalLabel(Number); if (!getPreliminary()) this->bind(L); } bool fixupIsPCRel(FixupKind Kind) const override { if (Kind == llvm::ELF::R_ARM_MOVW_PREL_NC) return true; if (Kind == llvm::ELF::R_ARM_MOVT_PREL) return true; return false; } /// Accessors to keep track of the number of bytes generated inside /// InstARM32::emit() methods, when run inside of /// InstARM32::emitUsingTextFixup(). void resetEmitTextSize() { EmitTextSize = 0; } void incEmitTextSize(size_t Amount) { EmitTextSize += Amount; } void decEmitTextSize(size_t Amount) { EmitTextSize -= Amount; } size_t getEmitTextSize() const { return EmitTextSize; } void bind(Label *label); // List of instructions implemented by integrated assembler. void adc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void add(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void and_(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void asr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void b(Label *L, CondARM32::Cond Cond); void bkpt(uint16_t Imm16); void bic(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void bl(const ConstantRelocatable *Target); void blx(const Operand *Target); void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL); void clz(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void cmn(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); void cmp(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); void dmb(IValueT Option); // Option is a 4-bit value. void eor(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); ldr(OpRt, OpAddress, Cond, TInfo); } void ldrex(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void ldrex(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); ldrex(OpRt, OpAddress, Cond, TInfo); } void lsl(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void lsr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void movt(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void mla(const Operand *OpRd, const Operand *OpRn, const Operand *OpRm, const Operand *OpRa, CondARM32::Cond Cond); void mls(const Operand *OpRd, const Operand *OpRn, const Operand *OpRm, const Operand *OpRa, CondARM32::Cond Cond); void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void mvn(const Operand *OpRd, const Operand *OpScc, CondARM32::Cond Cond); void nop(); void orr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void pop(const Variable *OpRt, CondARM32::Cond Cond); // Note: Registers is a bitset, where bit n corresponds to register Rn. void popList(const IValueT Registers, CondARM32::Cond Cond); void push(const Operand *OpRt, CondARM32::Cond Cond); // Note: Registers is a bitset, where bit n corresponds to register Rn. void pushList(const IValueT Registers, CondARM32::Cond Cond); void rbit(const Operand *OpRd, const Operand *OpRm, CondARM32::Cond Cond); void rev(const Operand *OpRd, const Operand *OpRm, CondARM32::Cond Cond); void rsb(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void rsc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); void sdiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); str(OpRt, OpAddress, Cond, TInfo); } void strex(const Operand *OpRd, const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void strex(const Operand *OpRd, const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); strex(OpRd, OpRt, OpAddress, Cond, TInfo); } void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond); // Implements sxtb/sxth depending on type of OpSrc0. void sxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond); void trap(); void tst(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); void udiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); void umull(const Operand *OpRdLo, const Operand *OpRdHi, const Operand *OpRn, const Operand *OpRm, CondARM32::Cond Cond); // Implements uxtb/uxth depending on type of OpSrc0. void uxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond); void vabss(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond); void vabsd(const Operand *OpDd, const Operand *OpDm, CondARM32::Cond Cond); void vabsq(const Operand *OpQd, const Operand *OpQm); void vaddd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm, CondARM32::Cond Cond); void vadds(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm, CondARM32::Cond Cond); // Integer vector add. void vaddqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); // Float vector add. void vaddqf(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vandq(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vbslq(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vceqqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vceqqs(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vcgeqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vcugeqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vcgeqs(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vcgtqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vcugtqi(const Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vcgtqs(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vcmpd(const Operand *OpDd, const Operand *OpDm, CondARM32::Cond cond); // Second argument of compare is zero (+0.0). void vcmpdz(const Operand *OpDd, CondARM32::Cond cond); void vcmps(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond cond); // Second argument of compare is zero (+0.0). void vcmpsz(const Operand *OpSd, CondARM32::Cond cond); void vcvtds(const Operand *OpDd, const Operand *OpSm, CondARM32::Cond Cond); // vcvt<c>.S32.F32 void vcvtis(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond); // vcvt<c>.S32.F64 void vcvtid(const Operand *OpSd, const Operand *OpDm, CondARM32::Cond Cond); // vcvt<c>.F64.S32 void vcvtdi(const Operand *OpDd, const Operand *OpSm, CondARM32::Cond Cond); // vcvt<c>.F64.U32 void vcvtdu(const Operand *OpDd, const Operand *OpSm, CondARM32::Cond Cond); void vcvtsd(const Operand *OpSd, const Operand *OpDm, CondARM32::Cond Cond); // vcvt<c>.F32.S32 void vcvtsi(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond); // vcvt<c>.F32.U32 void vcvtsu(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond); // vcvt<c>.U32.F64 void vcvtud(const Operand *OpSd, const Operand *OpDm, CondARM32::Cond Cond); // vcvt<c>.u32.f32 void vcvtus(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond); void vcvtqsi(const Operand *OpQd, const Operand *OpQm); void vcvtqsu(const Operand *OpQd, const Operand *OpQm); void vcvtqis(const Operand *OpQd, const Operand *OpQm); void vcvtqus(const Operand *OpQd, const Operand *OpQm); void vdivd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm, CondARM32::Cond Cond); void vdivs(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm, CondARM32::Cond Cond); void veord(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm); void veorq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); void vldrd(const Operand *OpDd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void vldrd(const Operand *OpDd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vldrd(OpDd, OpAddress, Cond, TInfo); } void vldrs(const Operand *OpSd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void vldrs(const Operand *OpSd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vldrs(OpSd, OpAddress, Cond, TInfo); } void vldrq(const Operand *OpQd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void vldrq(const Operand *OpQd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vldrq(OpQd, OpAddress, Cond, TInfo); } // ElmtSize = #bits in vector element. void vld1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn, const TargetInfo &TInfo); void vld1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn, const TargetInfo &TInfo); void vld1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vld1qr(ElmtSize, OpQd, OpRn, TInfo); } void vld1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vld1(ElmtSize, OpQd, OpRn, TInfo); } // Qn[i] = Imm for all i in vector. Returns true iff Imm can be defined as an // Imm8 using AdvSIMDExpandImm(). bool vmovqc(const Operand *OpQd, const ConstantInteger32 *Imm); // Dn = FpImm void vmovd(const Operand *OpDn, const OperandARM32FlexFpImm *OpFpImm, CondARM32::Cond Cond); // Dd = Dm void vmovdd(const Operand *OpDd, const Variable *OpDm, CondARM32::Cond Cond); // Dm = Rt:Rt2 void vmovdrr(const Operand *OpDm, const Operand *OpRt, const Operand *OpRt2, CondARM32::Cond Cond); // Qd[Index] = Rt void vmovqir(const Operand *OpQd, uint32_t Index, const Operand *OpRt, CondARM32::Cond Cond); // Qd[Index] = Sm void vmovqis(const Operand *OpQd, uint32_t Indx, const Operand *OpSm, CondARM32::Cond Cond); // Rt = Qm[Index] void vmovrqi(const Operand *OpRt, const Operand *OpQd, uint32_t Index, CondARM32::Cond Cond); // Rt:Rt2 = Dm void vmovrrd(const Operand *OpRt, const Operand *OpRt2, const Operand *OpDm, CondARM32::Cond Cond); // Rt = Sn void vmovrs(const Operand *OpRt, const Operand *OpSn, CondARM32::Cond Cond); // Sn = FpImm void vmovs(const Operand *OpSn, const OperandARM32FlexFpImm *OpFpImm, CondARM32::Cond Cond); // Sd = Sm void vmovss(const Operand *OpSd, const Variable *OpSm, CondARM32::Cond Cond); // Sd = Qm[Index] void vmovsqi(const Operand *OpSd, const Operand *OpQm, uint32_t Index, CondARM32::Cond Cond); // Sn = Rt void vmovsr(const Operand *OpSn, const Operand *OpRt, CondARM32::Cond Cond); void vmlad(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm, CondARM32::Cond Cond); void vmlas(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm, CondARM32::Cond Cond); void vmlsd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm, CondARM32::Cond Cond); void vmlss(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm, CondARM32::Cond Cond); // Uses APSR_nzcv as register void vmrsAPSR_nzcv(CondARM32::Cond Cond); void vmuld(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm, CondARM32::Cond Cond); // Integer vector multiply. void vmulqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); // Integer vector multiply high. void vmulh(Type ElmtTy, const Operand *OpQd, const Operand *OpQn, const Operand *OpQm, bool Unsigned); // Integer vector multiply add pairwise. void vmlap(Type ElmtTy, const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); // Vector element replication. void vdup(Type ElmtTy, const Operand *OpQd, const Operand *OpQn, IValueT Idx); // Vector interleave lower halves. void vzip(Type ElmtTy, const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); // Float vector multiply. void vmulqf(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); void vmuls(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm, CondARM32::Cond Cond); void vmvnq(const Operand *OpQd, const Operand *OpQm); void vmovlq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); void vmovhq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); void vmovhlq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); void vmovlhq(const Operand *OpQd, const Operand *OpQn, const Operand *OpQm); void vnegqs(const Operand *OpQd, const Operand *OpQm); void vnegqs(Type ElmtTy, const Operand *OpQd, const Operand *OpQm); void vorrq(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vpop(const Variable *OpBaseReg, SizeT NumConsecRegs, CondARM32::Cond Cond); void vpush(const Variable *OpBaseReg, SizeT NumConsecRegs, CondARM32::Cond Cond); void vshlqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vshlqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vshlqc(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const ConstantInteger32 *OpQn); void vshrqc(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const ConstantInteger32 *OpQn, InstARM32::FPSign Sign); void vsqrtd(const Operand *OpDd, const Operand *OpDm, CondARM32::Cond Cond); void vsqrts(const Operand *OpSd, const Operand *OpSm, CondARM32::Cond Cond); void vstrd(const Operand *OpDd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void vstrd(const Operand *OpDd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vstrd(OpDd, OpAddress, Cond, TInfo); } void vstrs(const Operand *OpSd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void vstrs(const Operand *OpSd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vstrs(OpSd, OpAddress, Cond, TInfo); } void vstrq(const Operand *OpQd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetInfo &TInfo); void vstrq(const Operand *OpQd, const Operand *OpAddress, CondARM32::Cond Cond, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vstrq(OpQd, OpAddress, Cond, TInfo); } // ElmtSize = #bits in vector element. void vst1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpAddress, const TargetInfo &TInfo); void vst1qr(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vst1qr(ElmtSize, OpQd, OpRn, TInfo); } void vst1(size_t ElmtSize, const Operand *OpQd, const Operand *OpAddress, const TargetInfo &TInfo); void vst1(size_t ElmtSize, const Operand *OpQd, const Operand *OpRn, const TargetLowering *Lowering) { const TargetInfo TInfo(Lowering); vst1(ElmtSize, OpQd, OpRn, TInfo); } void vsubd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm, CondARM32::Cond Cond); // Integer vector subtract. void vsubqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); // Integer vector saturating subtract. void vqsubqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vqsubqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); // Integer vector saturating add. void vqaddqi(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vqaddqu(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); // Integer vector packing with optional saturation. void vqmovn2(Type ElmtTy, const Operand *OpQd, const Operand *OpQm, const Operand *OpQn, bool Unsigned, bool Saturating); // Float vector subtract void vsubqf(const Operand *OpQd, const Operand *OpQm, const Operand *OpQn); void vsubs(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm, CondARM32::Cond Cond); static bool classof(const Assembler *Asm) { return Asm->getKind() == Asm_ARM32; } void emitTextInst(const std::string &Text, SizeT InstSize); private: ENABLE_MAKE_UNIQUE; const bool IsNonsfi; // A vector of pool-allocated x86 labels for CFG nodes. using LabelVector = std::vector<Label *>; LabelVector CfgNodeLabels; // A vector of pool-allocated x86 labels for Local labels. LabelVector LocalLabels; // Number of bytes emitted by InstARM32::emit() methods, when run inside // InstARM32::emitUsingTextFixup(). size_t EmitTextSize = 0; // Load/store multiple addressing mode. enum BlockAddressMode { // bit encoding P U W DA = (0 | 0 | 0) << 21, // decrement after IA = (0 | 4 | 0) << 21, // increment after DB = (8 | 0 | 0) << 21, // decrement before IB = (8 | 4 | 0) << 21, // increment before DA_W = (0 | 0 | 1) << 21, // decrement after with writeback to base IA_W = (0 | 4 | 1) << 21, // increment after with writeback to base DB_W = (8 | 0 | 1) << 21, // decrement before with writeback to base IB_W = (8 | 4 | 1) << 21 // increment before with writeback to base }; Label *getOrCreateLabel(SizeT Number, LabelVector &Labels); void bindCfgNodeLabel(const CfgNode *Node) override; // SIMD encoding for the vector ElmtTy. static IValueT encodeElmtType(Type ElmtTy); void emitInst(IValueT Value) { AssemblerBuffer::EnsureCapacity _(&Buffer); Buffer.emit<IValueT>(Value); } // List of possible checks to apply when calling emitType01() (below). enum EmitChecks { NoChecks, RdIsPcAndSetFlags }; // Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=InstType, // s=SetFlags, oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM // section A5.2.3). void emitType01(CondARM32::Cond Cond, IValueT InstType, IValueT Opcode, bool SetFlags, IValueT Rn, IValueT Rd, IValueT imm12, EmitChecks RuleChecks, const char *InstName); // Converts appropriate representation on a data operation, and then calls // emitType01 above. void emitType01(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, EmitChecks RuleChecks, const char *InstName); // Same as above, but the value for Rd and Rn have already been converted // into instruction values. void emitType01(CondARM32::Cond Cond, IValueT Opcode, IValueT OpRd, IValueT OpRn, const Operand *OpSrc1, bool SetFlags, EmitChecks RuleChecks, const char *InstName); void emitType05(CondARM32::Cond Cond, int32_t Offset, bool Link); // Emit ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond, // ooo=InstType, l=isLoad, b=isByte, and // aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that Address is assumed to be // defined by decodeAddress() in IceAssemblerARM32.cpp. void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad, bool IsByte, IValueT Rt, IValueT Address); // Emit ccccxxxxxxxxxxxxddddxxxxxxxxmmmm where cccc=Cond, // xxxxxxxxxxxx0000xxxxxxxx0000=Opcode, dddd=Rd, and mmmm=Rm. void emitRdRm(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRd, const Operand *OpRm, const char *InstName); // Emit ldr/ldrb/str/strb instruction with given address. void emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, IValueT Rt, const Operand *OpAddress, const TargetInfo &TInfo, const char *InstName); // Emit ldrh/ldrd/strh/strd instruction with given address using encoding 3. void emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, IValueT Rt, const Operand *OpAddress, const TargetInfo &TInfo, const char *InstName); // Emit cccc00011xxlnnnndddd11111001tttt where cccc=Cond, xx encodes type // size, l=IsLoad, nnnn=Rn (as defined by OpAddress), and tttt=Rt. void emitMemExOp(CondARM32::Cond, Type Ty, bool IsLoad, const Operand *OpRd, IValueT Rt, const Operand *OpAddress, const TargetInfo &TInfo, const char *InstName); // Pattern cccc100aaaalnnnnrrrrrrrrrrrrrrrr where cccc=Cond, // aaaa<<21=AddressMode, l=IsLoad, nnnn=BaseReg, and // rrrrrrrrrrrrrrrr is bitset of Registers. void emitMultiMemOp(CondARM32::Cond Cond, BlockAddressMode AddressMode, bool IsLoad, IValueT BaseReg, IValueT Registers); // Pattern ccccxxxxxDxxxxxxddddxxxxiiiiiiii where cccc=Cond, ddddD=BaseReg, // iiiiiiii=NumConsecRegs, and xxxxx0xxxxxx0000xxxx00000000=Opcode. void emitVStackOp(CondARM32::Cond Cond, IValueT Opcode, const Variable *OpBaseReg, SizeT NumConsecRegs); // Pattern cccc111xxDxxxxxxdddd101xxxMxmmmm where cccc=Cond, ddddD=Sd, // Mmmmm=Dm, and xx0xxxxxxdddd000xxx0x0000=Opcode. void emitVFPsd(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd, IValueT Dm); // Pattern cccc111xxDxxxxxxdddd101xxxMxmmmm where cccc=Cond, Ddddd=Dd, // mmmmM=Sm, and xx0xxxxxxdddd000xxx0x0000=Opcode. void emitVFPds(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, IValueT Sm); // Pattern 111100000D00nnnnddddttttssaammmm | Opcode where Ddddd=Dd, nnnn=Rn, // mmmmm=Rm, tttt=NumDRegs, ElmtSize in {8, 16, 32, 64) and defines ss, and // aa=Align. void emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn, IValueT Rm, DRegListSize NumDRegs, size_t ElmtSize, IValueT Align, const char *InstName); // Pattern 111100000D00nnnnddddss00aaaammmm | Opcode where Ddddd=Dd, nnnn=Rn, // mmmmm=Rm, ElmtSize in {8, 16, 32) and defines ss, and aa=Align. void emitVMem1Op(IValueT Opcode, IValueT Dd, IValueT Rn, IValueT Rm, size_t ElmtSize, IValueT Align, const char *InstName); // Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond, // x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm. void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, IValueT Rm); // cccc1110iiiennnntttt1011Njj10000 where cccc=Cond, tttt=Rt, Ndddd=2*Qn=Dn, // iii=Opcode1, jj=Opcode2, Opcode1Opcode2 encodes Index and the // corresponding element size of the vector element, and e=IsExtract. void emitInsertExtractInt(CondARM32::Cond Cond, const Operand *OpQn, uint32_t Index, const Operand *OpRt, bool IsExtract, const char *InstName); // cccc11101D110000dddd101001M0mmmm where cccc=Cond, ddddD=Sd, and mmmmM=Sm. // Assigns Sd the value of Sm. void emitMoveSS(CondARM32::Cond Cond, IValueT Sd, IValueT Sm); // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, // mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode. void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, IValueT Rm, IValueT Rs, bool SetFlags); // Pattern cccc0001101s0000ddddxxxxxtt0mmmm where cccc=Cond, s=SetFlags, // dddd=Rd, mmmm=Rm, tt=Shift, and xxxxx is defined by OpSrc1. OpSrc1 defines // either xxxxx=Imm5, or xxxxx=ssss0 where ssss=Rs. void emitShift(const CondARM32::Cond Cond, const OperandARM32::ShiftKind Shift, const Operand *OpRd, const Operand *OpRm, const Operand *OpSrc1, const bool SetFlags, const char *InstName); // Implements various forms of signed/unsigned extend value, using pattern // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode, // nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm. void emitSignExtend(CondARM32::Cond, IValueT Opcode, const Operand *OpRd, const Operand *OpSrc0, const char *InstName); // Implements various forms of vector (SIMD) operations. Implements pattern // 111100100D00nnnndddn00F0NQM0mmmm where Dddd=Dd, Nnnn=Dn, Mmmm=Dm, // Q=UseQRegs, F=IsFloatTy, and Opcode is unioned into the pattern. void emitSIMDBase(IValueT Opcode, IValueT Dd, IValueT Dn, IValueT Dm, bool UseQRegs, bool IsFloatTy); // Same as emitSIMDBase above, except ElmtShift=20 and ElmtSize is computed // from ElmtTy. void emitSIMD(IValueT Opcode, Type ElmtTy, IValueT Dd, IValueT Dn, IValueT Dm, bool UseQRegs); // Implements various integer forms of vector (SIMD) operations using Q // registers. Implements pattern 111100100D00nnn0ddd000F0N1M0mmm0 where // Dddd=Qd, Nnnn=Qn, Mmmm=Qm, F=IsFloatTy, and Opcode is unioned into the // pattern. void emitSIMDqqqBase(IValueT Opcode, const Operand *OpQd, const Operand *OpQn, const Operand *OpQm, bool IsFloatTy, const char *OpcodeName); // Same as emitSIMD above, except ElmtShift=20 and ElmtSize is computed from // ElmtTy. void emitSIMDqqq(IValueT Opcode, Type ElmtTy, const Operand *OpQd, const Operand *OpQn, const Operand *OpQm, const char *OpcodeName); // Implements various forms of vector (SIMD) shifts using Q registers. // Implements pattern 111100101Diiiiiidddd010101M1mmmm where Dddd=Qd, Mmmm=Qm, // iiiiii=Imm6, and Opcode is unioned into the pattern. void emitSIMDShiftqqc(IValueT Opcode, const Operand *OpQd, const Operand *OpQm, const IValueT Imm6, const char *OpcodeName); // Implements various forms of vector (SIMD) casts between (signed and // unsigned) integer and floating point types (f32). Implements pattern // 111100111D11ss11dddd011ooQM0mmmm where Dddd=Qd, Mmmm=Qm, 10=ss, op=00, 1=Q, // and Opcode is unioned into the pattern. void emitSIMDCvtqq(IValueT Opcode, const Operand *OpQd, const Operand *OpQm, const char *CvtName); // Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn, // ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from // OpSrc1, and xxxx=Opcode. void emitCompareOp(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRn, const Operand *OpSrc1, const char *CmpName); void emitBranch(Label *L, CondARM32::Cond, bool Link); // Returns the offset encoded in the branch instruction Inst. static IOffsetT decodeBranchOffset(IValueT Inst); // Implements movw/movt, generating pattern ccccxxxxxxxsiiiiddddiiiiiiiiiiii // where cccc=Cond, xxxxxxx<<21=Opcode, dddd=Rd, s=SetFlags, and // iiiiiiiiiiiiiiii=Imm16. void emitMovwt(CondARM32::Cond Cond, bool IsMovw, const Operand *OpRd, const Operand *OpSrc, const char *MovName); // Emit VFP instruction with 3 D registers. void emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpDd, const Operand *OpDn, const Operand *OpDm, const char *InstName); void emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, IValueT Dn, IValueT Dm); // Emit VFP instruction with 3 S registers. void emitVFPsss(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd, IValueT Sn, IValueT Sm); void emitVFPsss(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpSd, const Operand *OpSn, const Operand *OpSm, const char *InstName); }; } // end of namespace ARM32 } // end of namespace Ice #endif // SUBZERO_SRC_ICEASSEMBLERARM32_H