blob: 898a0746766a1fe6e9ca388afe1293c901ef5e29 [file] [log] [blame]
//===- 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