| //===- subzero/src/IceAssemblerMIPS32.h - Assembler for MIPS ----*- C++ -*-===// | 
 | // | 
 | //                        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 MIPS32. | 
 | /// | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #ifndef SUBZERO_SRC_ICEASSEMBLERMIPS32_H | 
 | #define SUBZERO_SRC_ICEASSEMBLERMIPS32_H | 
 |  | 
 | #include "IceAssembler.h" | 
 | #include "IceDefs.h" | 
 | #include "IceFixups.h" | 
 | #include "IceInstMIPS32.h" | 
 | #include "IceTargetLowering.h" | 
 |  | 
 | namespace Ice { | 
 | namespace MIPS32 { | 
 |  | 
 | using IValueT = uint32_t; | 
 | using IOffsetT = int32_t; | 
 |  | 
 | enum FPInstDataFormat { | 
 |   SinglePrecision = 16, | 
 |   DoublePrecision = 17, | 
 |   Word = 20, | 
 |   Long = 21 | 
 | }; | 
 |  | 
 | class MIPS32Fixup final : public AssemblerFixup { | 
 |   MIPS32Fixup &operator=(const MIPS32Fixup &) = delete; | 
 |   MIPS32Fixup(const MIPS32Fixup &) = default; | 
 |  | 
 | public: | 
 |   MIPS32Fixup() = default; | 
 |   size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final; | 
 |   void emitOffset(Assembler *Asm) const; | 
 | }; | 
 |  | 
 | class AssemblerMIPS32 : public Assembler { | 
 |   AssemblerMIPS32(const AssemblerMIPS32 &) = delete; | 
 |   AssemblerMIPS32 &operator=(const AssemblerMIPS32 &) = delete; | 
 |  | 
 | public: | 
 |   explicit AssemblerMIPS32(bool use_far_branches = false) | 
 |       : Assembler(Asm_MIPS32) { | 
 |     // This mode is only needed and implemented for MIPS32 and ARM. | 
 |     assert(!use_far_branches); | 
 |     (void)use_far_branches; | 
 |   } | 
 |   ~AssemblerMIPS32() override { | 
 |     if (BuildDefs::asserts()) { | 
 |       for (const Label *Label : CfgNodeLabels) { | 
 |         Label->finalCheck(); | 
 |       } | 
 |       for (const Label *Label : LocalLabels) { | 
 |         Label->finalCheck(); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   MIPS32Fixup *createMIPS32Fixup(const RelocOp Reloc, const Constant *RelOp); | 
 |  | 
 |   void trap(); | 
 |  | 
 |   void nop(); | 
 |  | 
 |   void emitRsRt(IValueT Opcode, const Operand *OpRs, const Operand *OpRt, | 
 |                 const char *InsnName); | 
 |  | 
 |   void emitRtRsImm16(IValueT Opcode, const Operand *OpRt, const Operand *OpRs, | 
 |                      uint32_t Imm, const char *InsnName); | 
 |  | 
 |   void emitRtRsImm16Rel(IValueT Opcode, const Operand *OpRt, | 
 |                         const Operand *OpRs, const Operand *OpImm, | 
 |                         const RelocOp Reloc, const char *InsnName); | 
 |  | 
 |   void emitFtRsImm16(IValueT Opcode, const Operand *OpFt, const Operand *OpRs, | 
 |                      uint32_t Imm, const char *InsnName); | 
 |  | 
 |   void emitRdRtSa(IValueT Opcode, const Operand *OpRd, const Operand *OpRt, | 
 |                   uint32_t Sa, const char *InsnName); | 
 |  | 
 |   void emitRdRsRt(IValueT Opcode, const Operand *OpRd, const Operand *OpRs, | 
 |                   const Operand *OpRt, const char *InsnName); | 
 |  | 
 |   void emitCOP1Fcmp(IValueT Opcode, FPInstDataFormat Format, | 
 |                     const Operand *OpFs, const Operand *OpFt, IValueT CC, | 
 |                     const char *InsnName); | 
 |  | 
 |   void emitCOP1FmtFsFd(IValueT Opcode, FPInstDataFormat Format, | 
 |                        const Operand *OpFd, const Operand *OpFs, | 
 |                        const char *InsnName); | 
 |  | 
 |   void emitCOP1FmtFtFsFd(IValueT Opcode, FPInstDataFormat Format, | 
 |                          const Operand *OpFd, const Operand *OpFs, | 
 |                          const Operand *OpFt, const char *InsnName); | 
 |  | 
 |   void emitCOP1FmtRtFsFd(IValueT Opcode, FPInstDataFormat Format, | 
 |                          const Operand *OpFd, const Operand *OpFs, | 
 |                          const Operand *OpRt, const char *InsnName); | 
 |  | 
 |   void emitCOP1MovRtFs(IValueT Opcode, const Operand *OpRt, const Operand *OpFs, | 
 |                        const char *InsnName); | 
 |  | 
 |   void emitBr(const CondMIPS32::Cond Cond, const Operand *OpRs, | 
 |               const Operand *OpRt, IOffsetT Offset); | 
 |  | 
 |   void abs_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void abs_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void addi(const Operand *OpRt, const Operand *OpRs, const uint32_t Imm); | 
 |  | 
 |   void add_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void add_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void addu(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void addiu(const Operand *OpRt, const Operand *OpRs, const uint32_t Imm); | 
 |  | 
 |   void addiu(const Operand *OpRt, const Operand *OpRs, const Operand *OpImm, | 
 |              const RelocOp Reloc); | 
 |  | 
 |   void and_(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void andi(const Operand *OpRt, const Operand *OpRs, const uint32_t Imm); | 
 |  | 
 |   void b(Label *TargetLabel); | 
 |  | 
 |   void c_eq_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_eq_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ole_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ole_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_olt_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_olt_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ueq_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ueq_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ule_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ule_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ult_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_ult_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_un_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void c_un_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void clz(const Operand *OpRd, const Operand *OpRs); | 
 |  | 
 |   void cvt_d_l(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void cvt_d_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void cvt_d_w(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void cvt_s_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void cvt_s_l(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void cvt_s_w(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void div(const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void div_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void div_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void divu(const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void jal(const ConstantRelocatable *Target); | 
 |  | 
 |   void jalr(const Operand *OpRs, const Operand *OpRd); | 
 |  | 
 |   void lui(const Operand *OpRt, const Operand *OpImm, const RelocOp Reloc); | 
 |  | 
 |   void ldc1(const Operand *OpRt, const Operand *OpBase, const Operand *OpOff, | 
 |             const RelocOp Reloc); | 
 |  | 
 |   void ll(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset); | 
 |  | 
 |   void lw(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset); | 
 |  | 
 |   void lwc1(const Operand *OpRt, const Operand *OpBase, const Operand *OpOff, | 
 |             const RelocOp Reloc); | 
 |  | 
 |   void mfc1(const Operand *OpRt, const Operand *OpFs); | 
 |  | 
 |   void mfhi(const Operand *OpRd); | 
 |  | 
 |   void mflo(const Operand *OpRd); | 
 |  | 
 |   void mov_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void mov_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void move(const Operand *OpRd, const Operand *OpRs); | 
 |  | 
 |   void movf(const Operand *OpRd, const Operand *OpRs, const Operand *OpCc); | 
 |  | 
 |   void movn(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void movn_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void movn_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void movt(const Operand *OpRd, const Operand *OpRs, const Operand *OpCc); | 
 |  | 
 |   void movz(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void movz_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void movz_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void mtc1(const Operand *OpRt, const Operand *OpFs); | 
 |  | 
 |   void mthi(const Operand *OpRs); | 
 |  | 
 |   void mtlo(const Operand *OpRs); | 
 |  | 
 |   void mul(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void mul_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void mul_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void mult(const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void multu(const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void nor(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void or_(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void ori(const Operand *OpRt, const Operand *OpRs, const uint32_t Imm); | 
 |  | 
 |   void ret(void); | 
 |  | 
 |   void sc(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset); | 
 |  | 
 |   void sll(const Operand *OpRd, const Operand *OpRt, const uint32_t Sa); | 
 |  | 
 |   void sllv(const Operand *OpRd, const Operand *OpRt, const Operand *OpRs); | 
 |  | 
 |   void slt(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void slti(const Operand *OpRt, const Operand *OpRs, const uint32_t Imm); | 
 |  | 
 |   void sltiu(const Operand *OpRt, const Operand *OpRs, const uint32_t Imm); | 
 |  | 
 |   void sltu(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void sqrt_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void sqrt_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void sra(const Operand *OpRd, const Operand *OpRt, const uint32_t Sa); | 
 |  | 
 |   void srav(const Operand *OpRd, const Operand *OpRt, const Operand *OpRs); | 
 |  | 
 |   void srl(const Operand *OpRd, const Operand *OpRt, const uint32_t Sa); | 
 |  | 
 |   void srlv(const Operand *OpRd, const Operand *OpRt, const Operand *OpRs); | 
 |  | 
 |   void sub_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void sub_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); | 
 |  | 
 |   void subu(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void sdc1(const Operand *OpRt, const Operand *OpBase, const Operand *OpOff, | 
 |             const RelocOp Reloc); | 
 |  | 
 |   void sw(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset); | 
 |  | 
 |   void swc1(const Operand *OpRt, const Operand *OpBase, const Operand *OpOff, | 
 |             const RelocOp Reloc); | 
 |  | 
 |   void sync(); | 
 |  | 
 |   void teq(const Operand *OpRs, const Operand *OpRt, const uint32_t TrapCode); | 
 |  | 
 |   void trunc_l_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void trunc_l_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void trunc_w_d(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void trunc_w_s(const Operand *OpFd, const Operand *OpFs); | 
 |  | 
 |   void xor_(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt); | 
 |  | 
 |   void xori(const Operand *OpRt, const Operand *OpRs, const uint32_t Imm); | 
 |  | 
 |   void bcc(const CondMIPS32::Cond Cond, const Operand *OpRs, | 
 |            const Operand *OpRt, Label *TargetLabel); | 
 |  | 
 |   void bzc(const CondMIPS32::Cond Cond, const Operand *OpRs, | 
 |            Label *TargetLabel); | 
 |  | 
 |   void alignFunction() override { | 
 |     const SizeT Align = 1 << getBundleAlignLog2Bytes(); | 
 |     SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align); | 
 |     constexpr SizeT InstSize = sizeof(IValueT); | 
 |     assert(BytesNeeded % InstMIPS32::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; | 
 |  | 
 |   void bind(Label *label); | 
 |  | 
 |   void emitTextInst(const std::string &Text, SizeT InstSize); | 
 |  | 
 |   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 InstMIPS32Label *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 { | 
 |     (void)Kind; | 
 |     return false; | 
 |   } | 
 |  | 
 |   static bool classof(const Assembler *Asm) { | 
 |     return Asm->getKind() == Asm_MIPS32; | 
 |   } | 
 |  | 
 | private: | 
 |   ENABLE_MAKE_UNIQUE; | 
 |  | 
 |   using LabelVector = std::vector<Label *>; | 
 |   LabelVector CfgNodeLabels; | 
 |   LabelVector LocalLabels; | 
 |  | 
 |   // Returns the offset encoded in the branch instruction Inst. | 
 |   static IOffsetT decodeBranchOffset(IValueT Inst); | 
 |  | 
 |   Label *getOrCreateLabel(SizeT Number, LabelVector &Labels); | 
 |  | 
 |   void bindCfgNodeLabel(const CfgNode *) override; | 
 |  | 
 |   void emitInst(IValueT Value) { | 
 |     AssemblerBuffer::EnsureCapacity _(&Buffer); | 
 |     Buffer.emit<IValueT>(Value); | 
 |   } | 
 | }; | 
 |  | 
 | } // end of namespace MIPS32 | 
 | } // end of namespace Ice | 
 |  | 
 | #endif // SUBZERO_SRC_ICEASSEMBLERMIPS32_H |