| Index: src/IceInstMIPS32.h
|
| diff --git a/src/IceInstMIPS32.h b/src/IceInstMIPS32.h
|
| index 1c4863f5cf853f74191fb4f5993faae158b7f555..fe3e274a83a9d0ad253e0d2a83284031c4d272cd 100644
|
| --- a/src/IceInstMIPS32.h
|
| +++ b/src/IceInstMIPS32.h
|
| @@ -26,6 +26,84 @@ namespace Ice {
|
|
|
| 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;
|
| @@ -33,12 +111,28 @@ class InstMIPS32 : public InstTarget {
|
| InstMIPS32 &operator=(const InstMIPS32 &) = delete;
|
|
|
| public:
|
| - enum InstKindMIPS32 { k__Start = Inst::Target, Ret };
|
| + enum InstKindMIPS32 {
|
| + k__Start = Inst::Target,
|
| + Addiu,
|
| + La,
|
| + Lui,
|
| + Mov, // actually a pseudo op for addi rd, rs, 0
|
| + Ori,
|
| + Ret
|
| + };
|
|
|
| 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;
|
| + }
|
| +
|
| + /// Shared emit routines for common forms of instructions.
|
| + static void emitUnaryopGPR(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) {}
|
| @@ -75,6 +169,166 @@ 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;
|
| +};
|
| +
|
| +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;
|
| +};
|
| +
|
| +typedef InstMIPS32Imm16<InstMIPS32::Addiu, true> InstMIPS32Addiu;
|
| +typedef InstMIPS32Imm16<InstMIPS32::Lui> InstMIPS32Lui;
|
| +typedef InstMIPS32UnaryopGPR<InstMIPS32::La> InstMIPS32La;
|
| +typedef InstMIPS32Imm16<InstMIPS32::Ori> InstMIPS32Ori;
|
| +
|
| +/// 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;
|
| +};
|
| +
|
| } // end of namespace Ice
|
|
|
| #endif // SUBZERO_SRC_ICEINSTMIPS32_H
|
|
|