blob: 7b93811cdc699c8895d0c03365d90b0870b9b5d7 [file] [log] [blame]
//===- subzero/src/IceInstMIPS32.h - MIPS32 machine instrs --*- 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 InstMIPS32 and OperandMIPS32 classes and their
/// subclasses.
///
/// This represents the machine instructions and operands used for MIPS32 code
/// selection.
///
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEINSTMIPS32_H
#define SUBZERO_SRC_ICEINSTMIPS32_H
#include "IceConditionCodesMIPS32.h"
#include "IceDefs.h"
#include "IceInst.h"
#include "IceInstMIPS32.def"
#include "IceOperand.h"
namespace Ice {
namespace MIPS32 {
class TargetMIPS32;
/// OperandMips32 extends the Operand hierarchy.
//
class OperandMIPS32 : public Operand {
OperandMIPS32() = delete;
OperandMIPS32(const OperandMIPS32 &) = delete;
OperandMIPS32 &operator=(const OperandMIPS32 &) = delete;
public:
enum OperandKindMIPS32 {
k__Start = Operand::kTarget,
kMem,
};
using Operand::dump;
void dump(const Cfg *, Ostream &Str) const override {
if (BuildDefs::dump())
Str << "<OperandMIPS32>";
}
protected:
OperandMIPS32(OperandKindMIPS32 Kind, Type Ty)
: Operand(static_cast<OperandKind>(Kind), Ty) {}
};
class OperandMIPS32Mem : public OperandMIPS32 {
OperandMIPS32Mem() = delete;
OperandMIPS32Mem(const OperandMIPS32Mem &) = delete;
OperandMIPS32Mem &operator=(const OperandMIPS32Mem &) = delete;
public:
/// Memory operand addressing mode.
/// The enum value also carries the encoding.
// TODO(jvoung): unify with the assembler.
enum AddrMode { Offset };
/// NOTE: The Variable-typed operands have to be registers.
///
/// Reg + Imm. The Immediate actually has a limited number of bits
/// for encoding, so check canHoldOffset first. It cannot handle
/// general Constant operands like ConstantRelocatable, since a relocatable
/// can potentially take up too many bits.
static OperandMIPS32Mem *create(Cfg *Func, Type Ty, Variable *Base,
ConstantInteger32 *ImmOffset,
AddrMode Mode = Offset) {
return new (Func->allocate<OperandMIPS32Mem>())
OperandMIPS32Mem(Func, Ty, Base, ImmOffset, Mode);
}
Variable *getBase() const { return Base; }
ConstantInteger32 *getOffset() const { return ImmOffset; }
AddrMode getAddrMode() const { return Mode; }
void emit(const Cfg *Func) const override;
using OperandMIPS32::dump;
static bool classof(const Operand *Operand) {
return Operand->getKind() == static_cast<OperandKind>(kMem);
}
/// Return true if a load/store instruction for an element of type Ty
/// can encode the Offset directly in the immediate field of the 32-bit
/// MIPS instruction. For some types, if the load is Sign extending, then
/// the range is reduced.
static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset);
void dump(const Cfg *Func, Ostream &Str) const override {
(void)Func;
(void)Str;
}
private:
OperandMIPS32Mem(Cfg *Func, Type Ty, Variable *Base,
ConstantInteger32 *ImmOffset, AddrMode Mode);
Variable *Base;
ConstantInteger32 *ImmOffset;
AddrMode Mode;
};
/// Base class for Mips instructions.
class InstMIPS32 : public InstTarget {
InstMIPS32() = delete;
InstMIPS32(const InstMIPS32 &) = delete;
InstMIPS32 &operator=(const InstMIPS32 &) = delete;
public:
enum InstKindMIPS32 {
k__Start = Inst::Target,
Add,
Add_d,
Add_s,
Addiu,
Addu,
And,
Andi,
Br,
Call,
Cvt_d_l,
Cvt_d_s,
Cvt_d_w,
Cvt_s_d,
Cvt_s_l,
Cvt_s_w,
Div,
Div_d,
Div_s,
Divu,
La,
Label,
Ldc1,
Lui,
Lw,
Lwc1,
Mfc1,
Mfhi,
Mflo,
Mov, // actually a pseudo op for addi rd, rs, 0
Mov_d,
Mov_s,
Mtc1,
Mthi,
Mtlo,
Mul,
Mul_d,
Mul_s,
Mult,
Multu,
Or,
Ori,
Ret,
Sdc1,
Sll,
Sllv,
Slt,
Slti,
Sltiu,
Sltu,
Sra,
Srav,
Srl,
Srlv,
Sub,
Sub_d,
Sub_s,
Subu,
Sw,
Swc1,
Trunc_l_d,
Trunc_l_s,
Trunc_w_d,
Trunc_w_s,
Xor,
Xori
};
static const char *getWidthString(Type Ty);
void dump(const Cfg *Func) const override;
void dumpOpcode(Ostream &Str, const char *Opcode, Type Ty) const {
Str << Opcode << "." << Ty;
}
// TODO(rkotler): while branching is not implemented
bool repointEdges(CfgNode *, CfgNode *) override { return true; }
/// Shared emit routines for common forms of instructions.
static void emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func);
static void emitUnaryopGPRFLoHi(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func);
static void emitUnaryopGPRTLoHi(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func);
static void emitTwoAddr(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func);
static void emitThreeAddr(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func);
static void emitThreeAddrLoHi(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func);
protected:
InstMIPS32(Cfg *Func, InstKindMIPS32 Kind, SizeT Maxsrcs, Variable *Dest)
: InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
static bool isClassof(const Inst *Inst, InstKindMIPS32 MyKind) {
return Inst->getKind() == static_cast<InstKind>(MyKind);
}
};
/// Ret pseudo-instruction. This is actually a "jr" instruction with an "ra"
/// register operand, but epilogue lowering will search for a Ret instead of a
/// generic "jr". This instruction also takes a Source operand (for non-void
/// returning functions) for liveness analysis, though a FakeUse before the ret
/// would do just as well.
// TODO(reed kotler): This needs was take from the ARM port and needs to be
// scrubbed in the future.
class InstMIPS32Ret : public InstMIPS32 {
InstMIPS32Ret() = delete;
InstMIPS32Ret(const InstMIPS32Ret &) = delete;
InstMIPS32Ret &operator=(const InstMIPS32Ret &) = delete;
public:
static InstMIPS32Ret *create(Cfg *Func, Variable *RA,
Variable *Source = nullptr) {
return new (Func->allocate<InstMIPS32Ret>())
InstMIPS32Ret(Func, RA, Source);
}
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); }
private:
InstMIPS32Ret(Cfg *Func, Variable *RA, Variable *Source);
};
/// Instructions of the form x := op(y).
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32UnaryopGPR : public InstMIPS32 {
InstMIPS32UnaryopGPR() = delete;
InstMIPS32UnaryopGPR(const InstMIPS32UnaryopGPR &) = delete;
InstMIPS32UnaryopGPR &operator=(const InstMIPS32UnaryopGPR &) = delete;
public:
static InstMIPS32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstMIPS32UnaryopGPR>())
InstMIPS32UnaryopGPR(Func, Dest, Src);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
emitUnaryopGPR(Opcode, this, Func);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpOpcode(Str, Opcode, getDest()->getType());
Str << " ";
dumpDest(Func);
Str << ", ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
protected:
InstMIPS32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src)
: InstMIPS32(Func, K, 1, Dest) {
addSource(Src);
}
private:
static const char *Opcode;
};
/// Instructions of the form opcode reg, reg.
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32TwoAddrFPR : public InstMIPS32 {
InstMIPS32TwoAddrFPR() = delete;
InstMIPS32TwoAddrFPR(const InstMIPS32TwoAddrFPR &) = delete;
InstMIPS32TwoAddrFPR &operator=(const InstMIPS32TwoAddrFPR &) = delete;
public:
static InstMIPS32TwoAddrFPR *create(Cfg *Func, Variable *Dest,
Variable *Src0) {
return new (Func->allocate<InstMIPS32TwoAddrFPR>())
InstMIPS32TwoAddrFPR(Func, Dest, Src0);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
emitTwoAddr(Opcode, this, Func);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = ";
dumpOpcode(Str, Opcode, getDest()->getType());
Str << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32TwoAddrFPR(Cfg *Func, Variable *Dest, Variable *Src0)
: InstMIPS32(Func, K, 1, Dest) {
addSource(Src0);
}
static const char *Opcode;
};
/// Instructions of the form opcode reg, reg.
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32TwoAddrGPR : public InstMIPS32 {
InstMIPS32TwoAddrGPR() = delete;
InstMIPS32TwoAddrGPR(const InstMIPS32TwoAddrGPR &) = delete;
InstMIPS32TwoAddrGPR &operator=(const InstMIPS32TwoAddrGPR &) = delete;
public:
static InstMIPS32TwoAddrGPR *create(Cfg *Func, Variable *Dest,
Variable *Src0) {
return new (Func->allocate<InstMIPS32TwoAddrGPR>())
InstMIPS32TwoAddrGPR(Func, Dest, Src0);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
emitTwoAddr(Opcode, this, Func);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = ";
dumpOpcode(Str, Opcode, getDest()->getType());
Str << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32TwoAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0)
: InstMIPS32(Func, K, 1, Dest) {
addSource(Src0);
}
static const char *Opcode;
};
/// Instructions of the form x := y op z. May have the side-effect of setting
/// status flags.
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32ThreeAddrFPR : public InstMIPS32 {
InstMIPS32ThreeAddrFPR() = delete;
InstMIPS32ThreeAddrFPR(const InstMIPS32ThreeAddrFPR &) = delete;
InstMIPS32ThreeAddrFPR &operator=(const InstMIPS32ThreeAddrFPR &) = delete;
public:
/// Create an ordinary binary-op instruction like add, and sub. Dest and Src1
/// must be registers.
static InstMIPS32ThreeAddrFPR *create(Cfg *Func, Variable *Dest,
Variable *Src0, Variable *Src1) {
return new (Func->allocate<InstMIPS32ThreeAddrFPR>())
InstMIPS32ThreeAddrFPR(Func, Dest, Src0, Src1);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
emitThreeAddr(Opcode, this, Func);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = ";
dumpOpcode(Str, Opcode, getDest()->getType());
Str << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32ThreeAddrFPR(Cfg *Func, Variable *Dest, Variable *Src0,
Variable *Src1)
: InstMIPS32(Func, K, 2, Dest) {
addSource(Src0);
addSource(Src1);
}
static const char *Opcode;
};
/// Instructions of the form x := y op z. May have the side-effect of setting
/// status flags.
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32ThreeAddrGPR : public InstMIPS32 {
InstMIPS32ThreeAddrGPR() = delete;
InstMIPS32ThreeAddrGPR(const InstMIPS32ThreeAddrGPR &) = delete;
InstMIPS32ThreeAddrGPR &operator=(const InstMIPS32ThreeAddrGPR &) = delete;
public:
/// Create an ordinary binary-op instruction like add, and sub. Dest and Src1
/// must be registers.
static InstMIPS32ThreeAddrGPR *create(Cfg *Func, Variable *Dest,
Variable *Src0, Variable *Src1) {
return new (Func->allocate<InstMIPS32ThreeAddrGPR>())
InstMIPS32ThreeAddrGPR(Func, Dest, Src0, Src1);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
emitThreeAddr(Opcode, this, Func);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = ";
dumpOpcode(Str, Opcode, getDest()->getType());
Str << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0,
Variable *Src1)
: InstMIPS32(Func, K, 2, Dest) {
addSource(Src0);
addSource(Src1);
}
static const char *Opcode;
};
// InstMIPS32Memory represents instructions which loads/stores data on memory
// Its format is "OPCODE GPR, OFFSET(BASE GPR)"
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32Memory : public InstMIPS32 {
InstMIPS32Memory() = delete;
InstMIPS32Memory(const InstMIPS32Memory &) = delete;
InstMIPS32Memory &operator=(const InstMIPS32Memory &) = delete;
public:
static InstMIPS32Memory *create(Cfg *Func, Variable *Value,
OperandMIPS32Mem *Mem) {
return new (Func->allocate<InstMIPS32Memory>())
InstMIPS32Memory(Func, Value, Mem);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 2);
Str << "\t" << Opcode << "\t";
getSrc(0)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << "\t" << Opcode << "\t";
Str << " ";
getSrc(1)->dump(Func);
Str << ", ";
getSrc(0)->dump(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32Memory(Cfg *Func, Variable *Value, OperandMIPS32Mem *Mem)
: InstMIPS32(Func, K, 2, nullptr) {
addSource(Value);
addSource(Mem);
}
static const char *Opcode;
};
// InstMIPS32Label represents an intra-block label that is the target of an
// intra-block branch. The offset between the label and the branch must be fit
// in the instruction immediate (considered "near").
class InstMIPS32Label : public InstMIPS32 {
InstMIPS32Label() = delete;
InstMIPS32Label(const InstMIPS32Label &) = delete;
InstMIPS32Label &operator=(const InstMIPS32Label &) = delete;
public:
static InstMIPS32Label *create(Cfg *Func, TargetMIPS32 *Target) {
return new (Func->allocate<InstMIPS32Label>())
InstMIPS32Label(Func, Target);
}
uint32_t getEmitInstCount() const override { return 0; }
GlobalString getLabelName() const { return Name; }
SizeT getNumber() const { return Number; }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Instr) { return isClassof(Instr, Label); }
private:
InstMIPS32Label(Cfg *Func, TargetMIPS32 *Target);
// RelocOffset *OffsetReloc = nullptr;
SizeT Number; // used for unique label generation.
GlobalString Name;
};
/// Direct branch instruction.
class InstMIPS32Br : public InstMIPS32 {
InstMIPS32Br() = delete;
InstMIPS32Br(const InstMIPS32Br &) = delete;
InstMIPS32Br &operator=(const InstMIPS32Br &) = delete;
public:
/// Create an unconditional branch to a node.
static InstMIPS32Br *create(Cfg *Func, CfgNode *Target) {
constexpr CfgNode *NoCondTarget = nullptr;
constexpr InstMIPS32Label *NoLabel = nullptr;
return new (Func->allocate<InstMIPS32Br>())
InstMIPS32Br(Func, NoCondTarget, Target, NoLabel, CondMIPS32::AL);
}
/// Create a conditional branch to the false node.
static InstMIPS32Br *create(Cfg *Func, CfgNode *TargetTrue,
CfgNode *TargetFalse, Operand *Src0,
Operand *Src1, CondMIPS32::Cond Cond) {
constexpr InstMIPS32Label *NoLabel = nullptr;
return new (Func->allocate<InstMIPS32Br>())
InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, Src1, NoLabel, Cond);
}
static InstMIPS32Br *create(Cfg *Func, CfgNode *TargetTrue,
CfgNode *TargetFalse, Operand *Src0,
CondMIPS32::Cond Cond) {
constexpr InstMIPS32Label *NoLabel = nullptr;
return new (Func->allocate<InstMIPS32Br>())
InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, NoLabel, Cond);
}
const CfgNode *getTargetTrue() const { return TargetTrue; }
const CfgNode *getTargetFalse() const { return TargetFalse; }
bool isUnconditionalBranch() const override {
return Predicate == CondMIPS32::AL;
}
bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override {
(void)OldNode;
(void)NewNode;
return true;
};
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override { (void)Func; };
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Instr) { return isClassof(Instr, Br); }
private:
InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
const InstMIPS32Label *Label, const CondMIPS32::Cond Cond);
InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
Operand *Src0, const InstMIPS32Label *Label,
const CondMIPS32::Cond Cond);
InstMIPS32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
Operand *Src0, Operand *Src1, const InstMIPS32Label *Label,
const CondMIPS32::Cond Cond);
const CfgNode *TargetTrue;
const CfgNode *TargetFalse;
const InstMIPS32Label *Label; // Intra-block branch target
const CondMIPS32::Cond Predicate;
};
class InstMIPS32Call : public InstMIPS32 {
InstMIPS32Call() = delete;
InstMIPS32Call(const InstMIPS32Call &) = delete;
InstMIPS32Call &operator=(const InstMIPS32Call &) = delete;
public:
static InstMIPS32Call *create(Cfg *Func, Variable *Dest,
Operand *CallTarget) {
return new (Func->allocate<InstMIPS32Call>())
InstMIPS32Call(Func, Dest, CallTarget);
}
Operand *getCallTarget() const { return getSrc(0); }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Call); }
private:
InstMIPS32Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
};
template <InstMIPS32::InstKindMIPS32 K, bool Signed = false>
class InstMIPS32Imm16 : public InstMIPS32 {
InstMIPS32Imm16() = delete;
InstMIPS32Imm16(const InstMIPS32Imm16 &) = delete;
InstMIPS32Imm16 &operator=(const InstMIPS32Imm16 &) = delete;
public:
static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, Operand *Source,
uint32_t Imm) {
return new (Func->allocate<InstMIPS32Imm16>())
InstMIPS32Imm16(Func, Dest, Source, Imm);
}
static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, uint32_t Imm) {
return new (Func->allocate<InstMIPS32Imm16>())
InstMIPS32Imm16(Func, Dest, Imm);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t" << Opcode << "\t";
getDest()->emit(Func);
if (getSrcSize() > 0) {
Str << ", ";
getSrc(0)->emit(Func);
}
Str << ", ";
if (Signed)
Str << (int32_t)Imm;
else
Str << Imm;
Str << "\n";
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << " ";
Str << "\t" << Opcode << "\t";
dumpDest(Func);
Str << ", ";
dumpSources(Func);
if (Signed)
Str << (int32_t)Imm;
else
Str << Imm;
Str << "\n";
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm)
: InstMIPS32(Func, K, 1, Dest), Imm(Imm) {
addSource(Source);
}
InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm)
: InstMIPS32(Func, K, 0, Dest), Imm(Imm) {}
static const char *Opcode;
const uint32_t Imm;
};
using InstMIPS32Add = InstMIPS32ThreeAddrGPR<InstMIPS32::Add>;
using InstMIPS32Add_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Add_d>;
using InstMIPS32Add_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Add_s>;
using InstMIPS32Addu = InstMIPS32ThreeAddrGPR<InstMIPS32::Addu>;
using InstMIPS32Addiu = InstMIPS32Imm16<InstMIPS32::Addiu, true>;
using InstMIPS32And = InstMIPS32ThreeAddrGPR<InstMIPS32::And>;
using InstMIPS32Andi = InstMIPS32Imm16<InstMIPS32::Andi>;
using InstMIPS32Cvt_d_s = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_s>;
using InstMIPS32Cvt_d_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_l>;
using InstMIPS32Cvt_d_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_w>;
using InstMIPS32Cvt_s_d = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_s_d>;
using InstMIPS32Cvt_s_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_s_l>;
using InstMIPS32Cvt_s_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_s_w>;
using InstMIPS32Div = InstMIPS32ThreeAddrGPR<InstMIPS32::Div>;
using InstMIPS32Div_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_d>;
using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_s>;
using InstMIPS32Divu = InstMIPS32ThreeAddrGPR<InstMIPS32::Divu>;
using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>;
using InstMIPS32Ldc1 = InstMIPS32Memory<InstMIPS32::Ldc1>;
using InstMIPS32Lui = InstMIPS32Imm16<InstMIPS32::Lui>;
using InstMIPS32Lw = InstMIPS32Memory<InstMIPS32::Lw>;
using InstMIPS32Lwc1 = InstMIPS32Memory<InstMIPS32::Lwc1>;
using InstMIPS32Mfc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mfc1>;
using InstMIPS32Mfhi = InstMIPS32UnaryopGPR<InstMIPS32::Mfhi>;
using InstMIPS32Mflo = InstMIPS32UnaryopGPR<InstMIPS32::Mflo>;
using InstMIPS32Mov_d = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_d>;
using InstMIPS32Mov_s = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_s>;
using InstMIPS32Mtc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mtc1>;
using InstMIPS32Mthi = InstMIPS32UnaryopGPR<InstMIPS32::Mthi>;
using InstMIPS32Mtlo = InstMIPS32UnaryopGPR<InstMIPS32::Mtlo>;
using InstMIPS32Mul = InstMIPS32ThreeAddrGPR<InstMIPS32::Mul>;
using InstMIPS32Mul_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Mul_d>;
using InstMIPS32Mul_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Mul_s>;
using InstMIPS32Mult = InstMIPS32ThreeAddrGPR<InstMIPS32::Mult>;
using InstMIPS32Multu = InstMIPS32ThreeAddrGPR<InstMIPS32::Multu>;
using InstMIPS32Or = InstMIPS32ThreeAddrGPR<InstMIPS32::Or>;
using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
using InstMIPS32Sdc1 = InstMIPS32Memory<InstMIPS32::Sdc1>;
using InstMIPS32Sll = InstMIPS32Imm16<InstMIPS32::Sll>;
using InstMIPS32Sllv = InstMIPS32ThreeAddrGPR<InstMIPS32::Sllv>;
using InstMIPS32Slt = InstMIPS32ThreeAddrGPR<InstMIPS32::Slt>;
using InstMIPS32Slti = InstMIPS32Imm16<InstMIPS32::Slti>;
using InstMIPS32Sltiu = InstMIPS32Imm16<InstMIPS32::Sltiu>;
using InstMIPS32Sltu = InstMIPS32ThreeAddrGPR<InstMIPS32::Sltu>;
using InstMIPS32Sra = InstMIPS32Imm16<InstMIPS32::Sra>;
using InstMIPS32Srav = InstMIPS32ThreeAddrGPR<InstMIPS32::Srav>;
using InstMIPS32Srl = InstMIPS32Imm16<InstMIPS32::Srl>;
using InstMIPS32Srlv = InstMIPS32ThreeAddrGPR<InstMIPS32::Srlv>;
using InstMIPS32Sub = InstMIPS32ThreeAddrGPR<InstMIPS32::Sub>;
using InstMIPS32Sub_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Sub_d>;
using InstMIPS32Sub_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Sub_s>;
using InstMIPS32Subu = InstMIPS32ThreeAddrGPR<InstMIPS32::Subu>;
using InstMIPS32Sw = InstMIPS32Memory<InstMIPS32::Sw>;
using InstMIPS32Swc1 = InstMIPS32Memory<InstMIPS32::Swc1>;
using InstMIPS32Trunc_l_d = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_l_d>;
using InstMIPS32Trunc_l_s = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_l_s>;
using InstMIPS32Trunc_w_d = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_w_d>;
using InstMIPS32Trunc_w_s = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_w_s>;
using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
using InstMIPS32Xor = InstMIPS32ThreeAddrGPR<InstMIPS32::Xor>;
using InstMIPS32Xori = InstMIPS32Imm16<InstMIPS32::Xori>;
/// Handles (some of) vmov's various formats.
class InstMIPS32Mov final : public InstMIPS32 {
InstMIPS32Mov() = delete;
InstMIPS32Mov(const InstMIPS32Mov &) = delete;
InstMIPS32Mov &operator=(const InstMIPS32Mov &) = delete;
public:
static InstMIPS32Mov *create(Cfg *Func, Variable *Dest, Operand *Src) {
return new (Func->allocate<InstMIPS32Mov>()) InstMIPS32Mov(Func, Dest, Src);
}
bool isRedundantAssign() const override {
return !isMultiDest() && !isMultiSource() &&
checkForRedundantAssign(getDest(), getSrc(0));
}
// bool isSimpleAssign() const override { return true; }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Mov); }
bool isMultiDest() const { return DestHi != nullptr; }
bool isMultiSource() const {
assert(getSrcSize() == 1 || getSrcSize() == 2);
return getSrcSize() == 2;
}
Variable *getDestHi() const { return DestHi; }
private:
InstMIPS32Mov(Cfg *Func, Variable *Dest, Operand *Src);
void emitMultiDestSingleSource(const Cfg *Func) const;
void emitSingleDestMultiSource(const Cfg *Func) const;
void emitSingleDestSingleSource(const Cfg *Func) const;
Variable *DestHi = nullptr;
};
// Declare partial template specializations of emit() methods that already have
// default implementations. Without this, there is the possibility of ODR
// violations and link errors.
template <> void InstMIPS32Mflo::emit(const Cfg *Func) const;
template <> void InstMIPS32Mfhi::emit(const Cfg *Func) const;
template <> void InstMIPS32Mtlo::emit(const Cfg *Func) const;
template <> void InstMIPS32Mthi::emit(const Cfg *Func) const;
template <> void InstMIPS32Mult::emit(const Cfg *Func) const;
template <> void InstMIPS32Multu::emit(const Cfg *Func) const;
} // end of namespace MIPS32
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEINSTMIPS32_H