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