| Index: src/mips/constants-mips.h
|
| diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
|
| index baaf546557c2883cf1486c4073b59bf3c5ec4ca4..d6400b65e420bdbd752078f040987ae1a7a36a0a 100644
|
| --- a/src/mips/constants-mips.h
|
| +++ b/src/mips/constants-mips.h
|
| @@ -866,8 +866,7 @@ static constexpr uint64_t OpcodeToBitNumber(Opcode opcode) {
|
| return 1ULL << (static_cast<uint32_t>(opcode) >> kOpcodeShift);
|
| }
|
|
|
| -
|
| -class Instruction {
|
| +class InstructionBase {
|
| public:
|
| enum {
|
| kInstrSize = 4,
|
| @@ -877,6 +876,9 @@ class Instruction {
|
| kPCReadOffset = 0
|
| };
|
|
|
| + // Instruction type.
|
| + enum Type { kRegisterType, kImmediateType, kJumpType, kUnsupported = -1 };
|
| +
|
| // Get the raw instruction bits.
|
| inline Instr InstructionBits() const {
|
| return *reinterpret_cast<const Instr*>(this);
|
| @@ -896,15 +898,6 @@ class Instruction {
|
| inline int Bits(int hi, int lo) const {
|
| return (InstructionBits() >> lo) & ((2U << (hi - lo)) - 1);
|
| }
|
| -
|
| - // Instruction type.
|
| - enum Type {
|
| - kRegisterType,
|
| - kImmediateType,
|
| - kJumpType,
|
| - kUnsupported = -1
|
| - };
|
| -
|
| enum TypeChecks { NORMAL, EXTRA };
|
|
|
|
|
| @@ -951,122 +944,140 @@ class Instruction {
|
| FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) |
|
| FunctionFieldToBitNumber(SELNEZ_S) | FunctionFieldToBitNumber(SYNC);
|
|
|
| - // Get the encoding type of the instruction.
|
| - inline Type InstructionType(TypeChecks checks = NORMAL) const;
|
| -
|
| // Accessors for the different named fields used in the MIPS encoding.
|
| inline Opcode OpcodeValue() const {
|
| return static_cast<Opcode>(
|
| Bits(kOpcodeShift + kOpcodeBits - 1, kOpcodeShift));
|
| }
|
|
|
| + inline int FunctionFieldRaw() const {
|
| + return InstructionBits() & kFunctionFieldMask;
|
| + }
|
| +
|
| + // Return the fields at their original place in the instruction encoding.
|
| + inline Opcode OpcodeFieldRaw() const {
|
| + return static_cast<Opcode>(InstructionBits() & kOpcodeMask);
|
| + }
|
| +
|
| + // Safe to call within InstructionType().
|
| + inline int RsFieldRawNoAssert() const {
|
| + return InstructionBits() & kRsFieldMask;
|
| + }
|
| +
|
| + inline int SaFieldRaw() const { return InstructionBits() & kSaFieldMask; }
|
| +
|
| + // Get the encoding type of the instruction.
|
| + inline Type InstructionType(TypeChecks checks = NORMAL) const;
|
| +
|
| + protected:
|
| + InstructionBase() {}
|
| +};
|
| +
|
| +template <class T>
|
| +class InstructionGetters : public T {
|
| + public:
|
| inline int RsValue() const {
|
| - DCHECK(InstructionType() == kRegisterType ||
|
| - InstructionType() == kImmediateType);
|
| - return Bits(kRsShift + kRsBits - 1, kRsShift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
| + this->InstructionType() == InstructionBase::kImmediateType);
|
| + return InstructionBase::Bits(kRsShift + kRsBits - 1, kRsShift);
|
| }
|
|
|
| inline int RtValue() const {
|
| - DCHECK(InstructionType() == kRegisterType ||
|
| - InstructionType() == kImmediateType);
|
| - return Bits(kRtShift + kRtBits - 1, kRtShift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
| + this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->Bits(kRtShift + kRtBits - 1, kRtShift);
|
| }
|
|
|
| inline int RdValue() const {
|
| - DCHECK(InstructionType() == kRegisterType);
|
| - return Bits(kRdShift + kRdBits - 1, kRdShift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
| + return this->Bits(kRdShift + kRdBits - 1, kRdShift);
|
| }
|
|
|
| inline int SaValue() const {
|
| - DCHECK(InstructionType() == kRegisterType);
|
| - return Bits(kSaShift + kSaBits - 1, kSaShift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
| + return this->Bits(kSaShift + kSaBits - 1, kSaShift);
|
| }
|
|
|
| inline int LsaSaValue() const {
|
| - DCHECK(InstructionType() == kRegisterType);
|
| - return Bits(kSaShift + kLsaSaBits - 1, kSaShift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
| + return this->Bits(kSaShift + kLsaSaBits - 1, kSaShift);
|
| }
|
|
|
| inline int FunctionValue() const {
|
| - DCHECK(InstructionType() == kRegisterType ||
|
| - InstructionType() == kImmediateType);
|
| - return Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
| + this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift);
|
| }
|
|
|
| inline int FdValue() const {
|
| - return Bits(kFdShift + kFdBits - 1, kFdShift);
|
| + return this->Bits(kFdShift + kFdBits - 1, kFdShift);
|
| }
|
|
|
| inline int FsValue() const {
|
| - return Bits(kFsShift + kFsBits - 1, kFsShift);
|
| + return this->Bits(kFsShift + kFsBits - 1, kFsShift);
|
| }
|
|
|
| inline int FtValue() const {
|
| - return Bits(kFtShift + kFtBits - 1, kFtShift);
|
| + return this->Bits(kFtShift + kFtBits - 1, kFtShift);
|
| }
|
|
|
| inline int FrValue() const {
|
| - return Bits(kFrShift + kFrBits -1, kFrShift);
|
| + return this->Bits(kFrShift + kFrBits - 1, kFrShift);
|
| }
|
|
|
| inline int Bp2Value() const {
|
| - DCHECK(InstructionType() == kRegisterType);
|
| - return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
| + return this->Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
|
| }
|
|
|
| // Float Compare condition code instruction bits.
|
| inline int FCccValue() const {
|
| - return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
|
| + return this->Bits(kFCccShift + kFCccBits - 1, kFCccShift);
|
| }
|
|
|
| // Float Branch condition code instruction bits.
|
| inline int FBccValue() const {
|
| - return Bits(kFBccShift + kFBccBits - 1, kFBccShift);
|
| + return this->Bits(kFBccShift + kFBccBits - 1, kFBccShift);
|
| }
|
|
|
| // Float Branch true/false instruction bit.
|
| inline int FBtrueValue() const {
|
| - return Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift);
|
| + return this->Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift);
|
| }
|
|
|
| // Return the fields at their original place in the instruction encoding.
|
| inline Opcode OpcodeFieldRaw() const {
|
| - return static_cast<Opcode>(InstructionBits() & kOpcodeMask);
|
| + return static_cast<Opcode>(this->InstructionBits() & kOpcodeMask);
|
| }
|
|
|
| inline int RsFieldRaw() const {
|
| - DCHECK(InstructionType() == kRegisterType ||
|
| - InstructionType() == kImmediateType);
|
| - return InstructionBits() & kRsFieldMask;
|
| - }
|
| -
|
| - // Same as above function, but safe to call within InstructionType().
|
| - inline int RsFieldRawNoAssert() const {
|
| - return InstructionBits() & kRsFieldMask;
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
| + this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->InstructionBits() & kRsFieldMask;
|
| }
|
|
|
| inline int RtFieldRaw() const {
|
| - DCHECK(InstructionType() == kRegisterType ||
|
| - InstructionType() == kImmediateType);
|
| - return InstructionBits() & kRtFieldMask;
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType ||
|
| + this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->InstructionBits() & kRtFieldMask;
|
| }
|
|
|
| inline int RdFieldRaw() const {
|
| - DCHECK(InstructionType() == kRegisterType);
|
| - return InstructionBits() & kRdFieldMask;
|
| + DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
| + return this->InstructionBits() & kRdFieldMask;
|
| }
|
|
|
| inline int SaFieldRaw() const {
|
| - return InstructionBits() & kSaFieldMask;
|
| + return this->InstructionBits() & kSaFieldMask;
|
| }
|
|
|
| inline int FunctionFieldRaw() const {
|
| - return InstructionBits() & kFunctionFieldMask;
|
| + return this->InstructionBits() & kFunctionFieldMask;
|
| }
|
|
|
| // Get the secondary field according to the opcode.
|
| inline int SecondaryValue() const {
|
| - Opcode op = OpcodeFieldRaw();
|
| + Opcode op = this->OpcodeFieldRaw();
|
| switch (op) {
|
| case SPECIAL:
|
| case SPECIAL2:
|
| @@ -1081,34 +1092,34 @@ class Instruction {
|
| }
|
|
|
| inline int32_t ImmValue(int bits) const {
|
| - DCHECK(InstructionType() == kImmediateType);
|
| - return Bits(bits - 1, 0);
|
| + DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->Bits(bits - 1, 0);
|
| }
|
|
|
| inline int32_t Imm16Value() const {
|
| - DCHECK(InstructionType() == kImmediateType);
|
| - return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
|
| }
|
|
|
| inline int32_t Imm18Value() const {
|
| - DCHECK(InstructionType() == kImmediateType);
|
| - return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
|
| }
|
|
|
| inline int32_t Imm19Value() const {
|
| - DCHECK(InstructionType() == kImmediateType);
|
| - return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
|
| }
|
|
|
| inline int32_t Imm21Value() const {
|
| - DCHECK(InstructionType() == kImmediateType);
|
| - return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
|
| + DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
| + return this->Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
|
| }
|
|
|
| inline int32_t Imm26Value() const {
|
| - DCHECK((InstructionType() == kJumpType) ||
|
| - (InstructionType() == kImmediateType));
|
| - return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
|
| + DCHECK((this->InstructionType() == InstructionBase::kJumpType) ||
|
| + (this->InstructionType() == InstructionBase::kImmediateType));
|
| + return this->Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
|
| }
|
|
|
| static bool IsForbiddenAfterBranchInstr(Instr instr);
|
| @@ -1116,7 +1127,7 @@ class Instruction {
|
| // Say if the instruction should not be used in a branch delay slot or
|
| // immediately after a compact branch.
|
| inline bool IsForbiddenAfterBranch() const {
|
| - return IsForbiddenAfterBranchInstr(InstructionBits());
|
| + return IsForbiddenAfterBranchInstr(this->InstructionBits());
|
| }
|
|
|
| inline bool IsForbiddenInBranchDelay() const {
|
| @@ -1127,17 +1138,15 @@ class Instruction {
|
| bool IsLinkingInstruction() const;
|
| // Say if the instruction is a break or a trap.
|
| bool IsTrap() const;
|
| +};
|
|
|
| - // Instructions are read of out a code stream. The only way to get a
|
| - // reference to an instruction is to convert a pointer. There is no way
|
| - // to allocate or create instances of class Instruction.
|
| - // Use the At(pc) function to create references to Instruction.
|
| +class Instruction : public InstructionGetters<InstructionBase> {
|
| + public:
|
| static Instruction* At(byte* pc) {
|
| return reinterpret_cast<Instruction*>(pc);
|
| }
|
|
|
| private:
|
| - // We need to prevent the creation of instances of class Instruction.
|
| DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
|
| };
|
|
|
| @@ -1156,8 +1165,8 @@ const int kBArgsSlotsSize = 0 * Instruction::kInstrSize;
|
|
|
| const int kBranchReturnOffset = 2 * Instruction::kInstrSize;
|
|
|
| -
|
| -Instruction::Type Instruction::InstructionType(TypeChecks checks) const {
|
| +InstructionBase::Type InstructionBase::InstructionType(
|
| + TypeChecks checks) const {
|
| if (checks == EXTRA) {
|
| if (OpcodeToBitNumber(OpcodeFieldRaw()) & kOpcodeImmediateTypeMask) {
|
| return kImmediateType;
|
| @@ -1240,6 +1249,118 @@ Instruction::Type Instruction::InstructionType(TypeChecks checks) const {
|
|
|
| #undef OpcodeToBitNumber
|
| #undef FunctionFieldToBitNumber
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// Instructions.
|
| +
|
| +template <class P>
|
| +bool InstructionGetters<P>::IsLinkingInstruction() const {
|
| + uint32_t op = this->OpcodeFieldRaw();
|
| + switch (op) {
|
| + case JAL:
|
| + return true;
|
| + case POP76:
|
| + if (this->RsFieldRawNoAssert() == JIALC)
|
| + return true; // JIALC
|
| + else
|
| + return false; // BNEZC
|
| + case REGIMM:
|
| + switch (this->RtFieldRaw()) {
|
| + case BGEZAL:
|
| + case BLTZAL:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| + case SPECIAL:
|
| + switch (this->FunctionFieldRaw()) {
|
| + case JALR:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +template <class P>
|
| +bool InstructionGetters<P>::IsTrap() const {
|
| + if (this->OpcodeFieldRaw() != SPECIAL) {
|
| + return false;
|
| + } else {
|
| + switch (this->FunctionFieldRaw()) {
|
| + case BREAK:
|
| + case TGE:
|
| + case TGEU:
|
| + case TLT:
|
| + case TLTU:
|
| + case TEQ:
|
| + case TNE:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| + }
|
| +}
|
| +
|
| +// static
|
| +template <class T>
|
| +bool InstructionGetters<T>::IsForbiddenAfterBranchInstr(Instr instr) {
|
| + Opcode opcode = static_cast<Opcode>(instr & kOpcodeMask);
|
| + switch (opcode) {
|
| + case J:
|
| + case JAL:
|
| + case BEQ:
|
| + case BNE:
|
| + case BLEZ: // POP06 bgeuc/bleuc, blezalc, bgezalc
|
| + case BGTZ: // POP07 bltuc/bgtuc, bgtzalc, bltzalc
|
| + case BEQL:
|
| + case BNEL:
|
| + case BLEZL: // POP26 bgezc, blezc, bgec/blec
|
| + case BGTZL: // POP27 bgtzc, bltzc, bltc/bgtc
|
| + case BC:
|
| + case BALC:
|
| + case POP10: // beqzalc, bovc, beqc
|
| + case POP30: // bnezalc, bnvc, bnec
|
| + case POP66: // beqzc, jic
|
| + case POP76: // bnezc, jialc
|
| + return true;
|
| + case REGIMM:
|
| + switch (instr & kRtFieldMask) {
|
| + case BLTZ:
|
| + case BGEZ:
|
| + case BLTZAL:
|
| + case BGEZAL:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| + break;
|
| + case SPECIAL:
|
| + switch (instr & kFunctionFieldMask) {
|
| + case JR:
|
| + case JALR:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| + break;
|
| + case COP1:
|
| + switch (instr & kRsFieldMask) {
|
| + case BC1:
|
| + case BC1EQZ:
|
| + case BC1NEZ:
|
| + return true;
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| + break;
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| } // namespace internal
|
| } // namespace v8
|
|
|
|
|