//===- 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