MIPS[64]: Add support for atomic binary operations in turbo fan
Bug: Change-Id: I5b5477b55f42cdfa7978bbe6b8610302f0ec41fb Reviewed-on: https://chromium-review.googlesource.com/612085 Reviewed-by: Miran Karić <Miran.Karic@imgtec.com> Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@imgtec.com> Cr-Commit-Position: refs/heads/master@{#47396}
This commit is contained in:
parent
8ee068388e
commit
89ac7fcdb4
@ -510,6 +510,41 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_ATOMIC_BINOP(bin_instr) \
|
||||
do { \
|
||||
Label binop; \
|
||||
__ addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ sync(); \
|
||||
__ bind(&binop); \
|
||||
__ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ bin_instr(i.TempRegister(1), i.OutputRegister(0), \
|
||||
Operand(i.InputRegister(2))); \
|
||||
__ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg)); \
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_ATOMIC_BINOP_EXT(sign_extend, size, bin_instr) \
|
||||
do { \
|
||||
Label binop; \
|
||||
__ addu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ andi(i.TempRegister(3), i.TempRegister(0), 0x3); \
|
||||
__ Subu(i.TempRegister(0), i.TempRegister(0), Operand(i.TempRegister(3))); \
|
||||
__ sll(i.TempRegister(3), i.TempRegister(3), 3); \
|
||||
__ sync(); \
|
||||
__ bind(&binop); \
|
||||
__ Ll(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3), \
|
||||
size, sign_extend); \
|
||||
__ bin_instr(i.TempRegister(2), i.OutputRegister(0), \
|
||||
Operand(i.InputRegister(2))); \
|
||||
__ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3), \
|
||||
size); \
|
||||
__ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg)); \
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_IEEE754_BINOP(name) \
|
||||
do { \
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL); \
|
||||
@ -1609,33 +1644,30 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kAtomicCompareExchangeInt16:
|
||||
case kAtomicCompareExchangeUint16:
|
||||
case kAtomicCompareExchangeWord32:
|
||||
case kAtomicAddInt8:
|
||||
case kAtomicAddUint8:
|
||||
case kAtomicAddInt16:
|
||||
case kAtomicAddUint16:
|
||||
case kAtomicAddWord32:
|
||||
case kAtomicSubInt8:
|
||||
case kAtomicSubUint8:
|
||||
case kAtomicSubInt16:
|
||||
case kAtomicSubUint16:
|
||||
case kAtomicSubWord32:
|
||||
case kAtomicAndInt8:
|
||||
case kAtomicAndUint8:
|
||||
case kAtomicAndInt16:
|
||||
case kAtomicAndUint16:
|
||||
case kAtomicAndWord32:
|
||||
case kAtomicOrInt8:
|
||||
case kAtomicOrUint8:
|
||||
case kAtomicOrInt16:
|
||||
case kAtomicOrUint16:
|
||||
case kAtomicOrWord32:
|
||||
case kAtomicXorInt8:
|
||||
case kAtomicXorUint8:
|
||||
case kAtomicXorInt16:
|
||||
case kAtomicXorUint16:
|
||||
case kAtomicXorWord32:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
#define ATOMIC_BINOP_CASE(op, inst) \
|
||||
case kAtomic##op##Int8: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(true, 8, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Uint8: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(false, 8, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Int16: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(true, 16, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Uint16: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(false, 16, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Word32: \
|
||||
ASSEMBLE_ATOMIC_BINOP(inst); \
|
||||
break;
|
||||
ATOMIC_BINOP_CASE(Add, Addu)
|
||||
ATOMIC_BINOP_CASE(Sub, Subu)
|
||||
ATOMIC_BINOP_CASE(And, And)
|
||||
ATOMIC_BINOP_CASE(Or, Or)
|
||||
ATOMIC_BINOP_CASE(Xor, Xor)
|
||||
#undef ATOMIC_BINOP_CASE
|
||||
case kMipsS128Zero: {
|
||||
CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
|
||||
__ xor_v(i.OutputSimd128Register(), i.OutputSimd128Register(),
|
||||
|
@ -1918,15 +1918,59 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitAtomicAdd(Node* node) { UNIMPLEMENTED(); }
|
||||
void InstructionSelector::VisitAtomicBinaryOperation(
|
||||
Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
|
||||
ArchOpcode uint16_op, ArchOpcode word32_op) {
|
||||
MipsOperandGenerator g(this);
|
||||
Node* base = node->InputAt(0);
|
||||
Node* index = node->InputAt(1);
|
||||
Node* value = node->InputAt(2);
|
||||
ArchOpcode opcode = kArchNop;
|
||||
MachineType type = AtomicOpRepresentationOf(node->op());
|
||||
if (type == MachineType::Int8()) {
|
||||
opcode = int8_op;
|
||||
} else if (type == MachineType::Uint8()) {
|
||||
opcode = uint8_op;
|
||||
} else if (type == MachineType::Int16()) {
|
||||
opcode = int16_op;
|
||||
} else if (type == MachineType::Uint16()) {
|
||||
opcode = uint16_op;
|
||||
} else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
|
||||
opcode = word32_op;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitAtomicSub(Node* node) { UNIMPLEMENTED(); }
|
||||
AddressingMode addressing_mode = kMode_MRI;
|
||||
InstructionOperand inputs[3];
|
||||
size_t input_count = 0;
|
||||
inputs[input_count++] = g.UseUniqueRegister(base);
|
||||
inputs[input_count++] = g.UseUniqueRegister(index);
|
||||
inputs[input_count++] = g.UseUniqueRegister(value);
|
||||
InstructionOperand outputs[1];
|
||||
outputs[0] = g.UseUniqueRegister(node);
|
||||
InstructionOperand temps[4];
|
||||
temps[0] = g.TempRegister();
|
||||
temps[1] = g.TempRegister();
|
||||
temps[2] = g.TempRegister();
|
||||
temps[3] = g.TempRegister();
|
||||
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
|
||||
Emit(code, 1, outputs, input_count, inputs, 4, temps);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitAtomicAnd(Node* node) { UNIMPLEMENTED(); }
|
||||
|
||||
void InstructionSelector::VisitAtomicOr(Node* node) { UNIMPLEMENTED(); }
|
||||
|
||||
void InstructionSelector::VisitAtomicXor(Node* node) { UNIMPLEMENTED(); }
|
||||
#define VISIT_ATOMIC_BINOP(op) \
|
||||
void InstructionSelector::VisitAtomic##op(Node* node) { \
|
||||
VisitAtomicBinaryOperation(node, kAtomic##op##Int8, kAtomic##op##Uint8, \
|
||||
kAtomic##op##Int16, kAtomic##op##Uint16, \
|
||||
kAtomic##op##Word32); \
|
||||
}
|
||||
VISIT_ATOMIC_BINOP(Add)
|
||||
VISIT_ATOMIC_BINOP(Sub)
|
||||
VISIT_ATOMIC_BINOP(And)
|
||||
VISIT_ATOMIC_BINOP(Or)
|
||||
VISIT_ATOMIC_BINOP(Xor)
|
||||
#undef VISIT_ATOMIC_BINOP
|
||||
|
||||
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
|
||||
UNREACHABLE();
|
||||
|
@ -546,6 +546,42 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_ATOMIC_BINOP(bin_instr) \
|
||||
do { \
|
||||
Label binop; \
|
||||
__ Daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ sync(); \
|
||||
__ bind(&binop); \
|
||||
__ Ll(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ bin_instr(i.TempRegister(1), i.OutputRegister(0), \
|
||||
Operand(i.InputRegister(2))); \
|
||||
__ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg)); \
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_ATOMIC_BINOP_EXT(sign_extend, size, bin_instr) \
|
||||
do { \
|
||||
Label binop; \
|
||||
__ daddu(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
|
||||
__ andi(i.TempRegister(3), i.TempRegister(0), 0x3); \
|
||||
__ Dsubu(i.TempRegister(0), i.TempRegister(0), \
|
||||
Operand(i.TempRegister(3))); \
|
||||
__ sll(i.TempRegister(3), i.TempRegister(3), 3); \
|
||||
__ sync(); \
|
||||
__ bind(&binop); \
|
||||
__ Ll(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3), \
|
||||
size, sign_extend); \
|
||||
__ bin_instr(i.TempRegister(2), i.OutputRegister(0), \
|
||||
Operand(i.InputRegister(2))); \
|
||||
__ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3), \
|
||||
size); \
|
||||
__ Sc(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
|
||||
__ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg)); \
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_IEEE754_BINOP(name) \
|
||||
do { \
|
||||
FrameScope scope(tasm(), StackFrame::MANUAL); \
|
||||
@ -1889,33 +1925,30 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kAtomicCompareExchangeInt16:
|
||||
case kAtomicCompareExchangeUint16:
|
||||
case kAtomicCompareExchangeWord32:
|
||||
case kAtomicAddInt8:
|
||||
case kAtomicAddUint8:
|
||||
case kAtomicAddInt16:
|
||||
case kAtomicAddUint16:
|
||||
case kAtomicAddWord32:
|
||||
case kAtomicSubInt8:
|
||||
case kAtomicSubUint8:
|
||||
case kAtomicSubInt16:
|
||||
case kAtomicSubUint16:
|
||||
case kAtomicSubWord32:
|
||||
case kAtomicAndInt8:
|
||||
case kAtomicAndUint8:
|
||||
case kAtomicAndInt16:
|
||||
case kAtomicAndUint16:
|
||||
case kAtomicAndWord32:
|
||||
case kAtomicOrInt8:
|
||||
case kAtomicOrUint8:
|
||||
case kAtomicOrInt16:
|
||||
case kAtomicOrUint16:
|
||||
case kAtomicOrWord32:
|
||||
case kAtomicXorInt8:
|
||||
case kAtomicXorUint8:
|
||||
case kAtomicXorInt16:
|
||||
case kAtomicXorUint16:
|
||||
case kAtomicXorWord32:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
#define ATOMIC_BINOP_CASE(op, inst) \
|
||||
case kAtomic##op##Int8: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(true, 8, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Uint8: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(false, 8, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Int16: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(true, 16, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Uint16: \
|
||||
ASSEMBLE_ATOMIC_BINOP_EXT(false, 16, inst); \
|
||||
break; \
|
||||
case kAtomic##op##Word32: \
|
||||
ASSEMBLE_ATOMIC_BINOP(inst); \
|
||||
break;
|
||||
ATOMIC_BINOP_CASE(Add, Addu)
|
||||
ATOMIC_BINOP_CASE(Sub, Subu)
|
||||
ATOMIC_BINOP_CASE(And, And)
|
||||
ATOMIC_BINOP_CASE(Or, Or)
|
||||
ATOMIC_BINOP_CASE(Xor, Xor)
|
||||
#undef ATOMIC_BINOP_CASE
|
||||
case kMips64AssertEqual:
|
||||
__ Assert(eq, static_cast<BailoutReason>(i.InputOperand(2).immediate()),
|
||||
i.InputRegister(0), Operand(i.InputRegister(1)));
|
||||
|
@ -2611,15 +2611,59 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitAtomicAdd(Node* node) { UNIMPLEMENTED(); }
|
||||
void InstructionSelector::VisitAtomicBinaryOperation(
|
||||
Node* node, ArchOpcode int8_op, ArchOpcode uint8_op, ArchOpcode int16_op,
|
||||
ArchOpcode uint16_op, ArchOpcode word32_op) {
|
||||
Mips64OperandGenerator g(this);
|
||||
Node* base = node->InputAt(0);
|
||||
Node* index = node->InputAt(1);
|
||||
Node* value = node->InputAt(2);
|
||||
ArchOpcode opcode = kArchNop;
|
||||
MachineType type = AtomicOpRepresentationOf(node->op());
|
||||
if (type == MachineType::Int8()) {
|
||||
opcode = int8_op;
|
||||
} else if (type == MachineType::Uint8()) {
|
||||
opcode = uint8_op;
|
||||
} else if (type == MachineType::Int16()) {
|
||||
opcode = int16_op;
|
||||
} else if (type == MachineType::Uint16()) {
|
||||
opcode = uint16_op;
|
||||
} else if (type == MachineType::Int32() || type == MachineType::Uint32()) {
|
||||
opcode = word32_op;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitAtomicSub(Node* node) { UNIMPLEMENTED(); }
|
||||
AddressingMode addressing_mode = kMode_MRI;
|
||||
InstructionOperand inputs[3];
|
||||
size_t input_count = 0;
|
||||
inputs[input_count++] = g.UseUniqueRegister(base);
|
||||
inputs[input_count++] = g.UseUniqueRegister(index);
|
||||
inputs[input_count++] = g.UseUniqueRegister(value);
|
||||
InstructionOperand outputs[1];
|
||||
outputs[0] = g.UseUniqueRegister(node);
|
||||
InstructionOperand temps[4];
|
||||
temps[0] = g.TempRegister();
|
||||
temps[1] = g.TempRegister();
|
||||
temps[2] = g.TempRegister();
|
||||
temps[3] = g.TempRegister();
|
||||
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
|
||||
Emit(code, 1, outputs, input_count, inputs, 4, temps);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitAtomicAnd(Node* node) { UNIMPLEMENTED(); }
|
||||
|
||||
void InstructionSelector::VisitAtomicOr(Node* node) { UNIMPLEMENTED(); }
|
||||
|
||||
void InstructionSelector::VisitAtomicXor(Node* node) { UNIMPLEMENTED(); }
|
||||
#define VISIT_ATOMIC_BINOP(op) \
|
||||
void InstructionSelector::VisitAtomic##op(Node* node) { \
|
||||
VisitAtomicBinaryOperation(node, kAtomic##op##Int8, kAtomic##op##Uint8, \
|
||||
kAtomic##op##Int16, kAtomic##op##Uint16, \
|
||||
kAtomic##op##Word32); \
|
||||
}
|
||||
VISIT_ATOMIC_BINOP(Add)
|
||||
VISIT_ATOMIC_BINOP(Sub)
|
||||
VISIT_ATOMIC_BINOP(And)
|
||||
VISIT_ATOMIC_BINOP(Or)
|
||||
VISIT_ATOMIC_BINOP(Xor)
|
||||
#undef VISIT_ATOMIC_BINOP
|
||||
|
||||
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
|
||||
UNREACHABLE();
|
||||
|
@ -1151,6 +1151,16 @@ void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
|
||||
emit(instr, is_compact_branch);
|
||||
}
|
||||
|
||||
void Assembler::GenInstrImmediate(Opcode opcode, Register base, Register rt,
|
||||
int32_t offset9, int bit6,
|
||||
SecondaryField func) {
|
||||
DCHECK(base.is_valid() && rt.is_valid() && is_int9(offset9) &&
|
||||
is_uint1(bit6));
|
||||
Instr instr = opcode | (base.code() << kBaseShift) | (rt.code() << kRtShift) |
|
||||
((offset9 << kImm9Shift) & kImm9Mask) | bit6 << kBit6Shift |
|
||||
func;
|
||||
emit(instr);
|
||||
}
|
||||
|
||||
void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
|
||||
int32_t j,
|
||||
@ -2147,6 +2157,28 @@ void Assembler::swr(Register rd, const MemOperand& rs) {
|
||||
GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
|
||||
void Assembler::ll(Register rd, const MemOperand& rs) {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 0, LL_R6);
|
||||
} else {
|
||||
DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
|
||||
IsMipsArchVariant(kMips32r2));
|
||||
DCHECK(is_int16(rs.offset_));
|
||||
GenInstrImmediate(LL, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::sc(Register rd, const MemOperand& rs) {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 0, SC_R6);
|
||||
} else {
|
||||
DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
|
||||
IsMipsArchVariant(kMips32r2));
|
||||
GenInstrImmediate(SC, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::lui(Register rd, int32_t j) {
|
||||
DCHECK(is_uint16(j));
|
||||
|
@ -1015,6 +1015,10 @@ class Assembler : public AssemblerBase {
|
||||
void swl(Register rd, const MemOperand& rs);
|
||||
void swr(Register rd, const MemOperand& rs);
|
||||
|
||||
// ----------Atomic instructions--------------
|
||||
|
||||
void ll(Register rd, const MemOperand& rs);
|
||||
void sc(Register rd, const MemOperand& rs);
|
||||
|
||||
// ---------PC-Relative-instructions-----------
|
||||
|
||||
@ -2180,6 +2184,8 @@ class Assembler : public AssemblerBase {
|
||||
void GenInstrImmediate(
|
||||
Opcode opcode, Register r1, FPURegister r2, int32_t j,
|
||||
CompactBranchType is_compact_branch = CompactBranchType::NO);
|
||||
void GenInstrImmediate(Opcode opcode, Register base, Register rt,
|
||||
int32_t offset9, int bit6, SecondaryField func);
|
||||
void GenInstrImmediate(
|
||||
Opcode opcode, Register rs, int32_t offset21,
|
||||
CompactBranchType is_compact_branch = CompactBranchType::NO);
|
||||
|
@ -313,7 +313,13 @@ const int kFunctionBits = 6;
|
||||
const int kLuiShift = 16;
|
||||
const int kBp2Shift = 6;
|
||||
const int kBp2Bits = 2;
|
||||
const int kBaseShift = 21;
|
||||
const int kBaseBits = 5;
|
||||
const int kBit6Shift = 6;
|
||||
const int kBit6Bits = 1;
|
||||
|
||||
const int kImm9Shift = 7;
|
||||
const int kImm9Bits = 9;
|
||||
const int kImm16Shift = 0;
|
||||
const int kImm16Bits = 16;
|
||||
const int kImm18Shift = 0;
|
||||
@ -365,6 +371,7 @@ const int kWdShift = 6;
|
||||
// ----- Miscellaneous useful masks.
|
||||
// Instruction bit masks.
|
||||
const int kOpcodeMask = ((1 << kOpcodeBits) - 1) << kOpcodeShift;
|
||||
const int kImm9Mask = ((1 << kImm9Bits) - 1) << kImm9Shift;
|
||||
const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift;
|
||||
const int kImm18Mask = ((1 << kImm18Bits) - 1) << kImm18Shift;
|
||||
const int kImm19Mask = ((1 << kImm19Bits) - 1) << kImm19Shift;
|
||||
@ -444,6 +451,7 @@ enum Opcode : uint32_t {
|
||||
SW = ((5U << 3) + 3) << kOpcodeShift,
|
||||
SWR = ((5U << 3) + 6) << kOpcodeShift,
|
||||
|
||||
LL = ((6U << 3) + 0) << kOpcodeShift,
|
||||
LWC1 = ((6U << 3) + 1) << kOpcodeShift,
|
||||
BC = ((6U << 3) + 2) << kOpcodeShift,
|
||||
LDC1 = ((6U << 3) + 5) << kOpcodeShift,
|
||||
@ -451,6 +459,7 @@ enum Opcode : uint32_t {
|
||||
|
||||
PREF = ((6U << 3) + 3) << kOpcodeShift,
|
||||
|
||||
SC = ((7U << 3) + 0) << kOpcodeShift,
|
||||
SWC1 = ((7U << 3) + 1) << kOpcodeShift,
|
||||
BALC = ((7U << 3) + 2) << kOpcodeShift,
|
||||
PCREL = ((7U << 3) + 3) << kOpcodeShift,
|
||||
@ -539,6 +548,8 @@ enum SecondaryField : uint32_t {
|
||||
EXT = ((0U << 3) + 0),
|
||||
INS = ((0U << 3) + 4),
|
||||
BSHFL = ((4U << 3) + 0),
|
||||
SC_R6 = ((4U << 3) + 6),
|
||||
LL_R6 = ((6U << 3) + 6),
|
||||
|
||||
// SPECIAL3 Encoding of sa Field.
|
||||
BITSWAP = ((0U << 3) + 0),
|
||||
@ -1398,6 +1409,11 @@ class InstructionGetters : public T {
|
||||
return this->Bits(kRdShift + kRdBits - 1, kRdShift);
|
||||
}
|
||||
|
||||
inline int BaseValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kBaseShift + kBaseBits - 1, kBaseShift);
|
||||
}
|
||||
|
||||
inline int SaValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->Bits(kSaShift + kSaBits - 1, kSaShift);
|
||||
@ -1513,6 +1529,11 @@ class InstructionGetters : public T {
|
||||
return this->Bits(bits - 1, 0);
|
||||
}
|
||||
|
||||
inline int32_t Imm9Value() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm9Shift + kImm9Bits - 1, kImm9Shift);
|
||||
}
|
||||
|
||||
inline int32_t Imm16Value() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
|
||||
@ -1715,6 +1736,11 @@ InstructionBase::Type InstructionBase::InstructionType() const {
|
||||
return kUnsupported;
|
||||
}
|
||||
}
|
||||
case LL_R6:
|
||||
case SC_R6: {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
return kImmediateType;
|
||||
}
|
||||
default:
|
||||
return kUnsupported;
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ class Decoder {
|
||||
void PrintBp2(Instruction* instr);
|
||||
void PrintFunction(Instruction* instr);
|
||||
void PrintSecondaryField(Instruction* instr);
|
||||
void PrintUImm9(Instruction* instr);
|
||||
void PrintSImm9(Instruction* instr);
|
||||
void PrintUImm16(Instruction* instr);
|
||||
void PrintSImm16(Instruction* instr);
|
||||
void PrintXImm16(Instruction* instr);
|
||||
@ -134,6 +136,7 @@ class Decoder {
|
||||
void DecodeTypeRegisterSPECIAL3(Instruction* instr);
|
||||
void DecodeTypeRegister(Instruction* instr);
|
||||
void DecodeTypeImmediate(Instruction* instr);
|
||||
void DecodeTypeImmediateSPECIAL3(Instruction* instr);
|
||||
void DecodeTypeJump(Instruction* instr);
|
||||
void DecodeTypeMsaI8(Instruction* instr);
|
||||
void DecodeTypeMsaI5(Instruction* instr);
|
||||
@ -305,6 +308,17 @@ void Decoder::PrintBp2(Instruction* instr) {
|
||||
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp2);
|
||||
}
|
||||
|
||||
// Print 9-bit unsigned immediate value.
|
||||
void Decoder::PrintUImm9(Instruction* instr) {
|
||||
int32_t imm = instr->Imm9Value();
|
||||
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
|
||||
}
|
||||
|
||||
// Print 9-bit signed immediate value.
|
||||
void Decoder::PrintSImm9(Instruction* instr) {
|
||||
int32_t imm = ((instr->Imm9Value()) << 23) >> 23;
|
||||
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
|
||||
}
|
||||
|
||||
// Print 16-bit unsigned immediate value.
|
||||
void Decoder::PrintUImm16(Instruction* instr) {
|
||||
@ -884,6 +898,16 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm8"));
|
||||
PrintMsaImm8(instr);
|
||||
return 4;
|
||||
} else if (format[3] == '9') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm9"));
|
||||
if (format[4] == 'u') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm9u"));
|
||||
PrintUImm9(instr);
|
||||
} else if (format[4] == 's') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm9s"));
|
||||
PrintSImm9(instr);
|
||||
}
|
||||
return 5;
|
||||
} else if (format[3] == 'b') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "immb"));
|
||||
PrintMsaImmBit(instr);
|
||||
@ -1644,6 +1668,28 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::DecodeTypeImmediateSPECIAL3(Instruction* instr) {
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case LL_R6: {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Format(instr, "ll 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SC_R6: {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Format(instr, "sc 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
switch (instr->OpcodeFieldRaw()) {
|
||||
@ -1894,6 +1940,20 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
case SWR:
|
||||
Format(instr, "swr 'rt, 'imm16s('rs)");
|
||||
break;
|
||||
case LL:
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "ll 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case SC:
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "sc 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case LWC1:
|
||||
Format(instr, "lwc1 'ft, 'imm16s('rs)");
|
||||
break;
|
||||
@ -1935,6 +1995,9 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPECIAL3:
|
||||
DecodeTypeImmediateSPECIAL3(instr);
|
||||
break;
|
||||
case MSA:
|
||||
switch (instr->MSAMinorOpcodeField()) {
|
||||
case kMsaMinorI8:
|
||||
|
@ -778,13 +778,7 @@ void TurboAssembler::Nor(Register rd, Register rs, const Operand& rt) {
|
||||
}
|
||||
|
||||
void TurboAssembler::Neg(Register rs, const Operand& rt) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
DCHECK(rt.is_reg());
|
||||
DCHECK(!scratch.is(rs));
|
||||
DCHECK(!scratch.is(rt.rm()));
|
||||
li(scratch, -1);
|
||||
xor_(rs, rt.rm(), scratch);
|
||||
subu(rs, zero_reg, rt.rm());
|
||||
}
|
||||
|
||||
void TurboAssembler::Slt(Register rd, Register rs, const Operand& rt) {
|
||||
@ -1212,6 +1206,36 @@ void TurboAssembler::Sdc1(FPURegister fd, const MemOperand& src) {
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Ll(Register rd, const MemOperand& rs) {
|
||||
bool is_one_instruction = IsMipsArchVariant(kMips32r6)
|
||||
? is_int9(rs.offset())
|
||||
: is_int16(rs.offset());
|
||||
if (is_one_instruction) {
|
||||
ll(rd, rs);
|
||||
} else {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
li(scratch, rs.offset());
|
||||
addu(scratch, scratch, rs.rm());
|
||||
ll(rd, MemOperand(scratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Sc(Register rd, const MemOperand& rs) {
|
||||
bool is_one_instruction = IsMipsArchVariant(kMips32r6)
|
||||
? is_int9(rs.offset())
|
||||
: is_int16(rs.offset());
|
||||
if (is_one_instruction) {
|
||||
sc(rd, rs);
|
||||
} else {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
li(scratch, rs.offset());
|
||||
addu(scratch, scratch, rs.rm());
|
||||
sc(rd, MemOperand(scratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::li(Register dst, Handle<HeapObject> value, LiFlags mode) {
|
||||
li(dst, Operand(value), mode);
|
||||
}
|
||||
@ -1536,6 +1560,36 @@ void TurboAssembler::Ins(Register rt, Register rs, uint16_t pos,
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::ExtractBits(Register dest, Register source, Register pos,
|
||||
int size, bool sign_extend) {
|
||||
srav(dest, source, pos);
|
||||
Ext(dest, dest, 0, size);
|
||||
if (size == 8) {
|
||||
if (sign_extend) {
|
||||
Seb(dest, dest);
|
||||
}
|
||||
} else if (size == 16) {
|
||||
if (sign_extend) {
|
||||
Seh(dest, dest);
|
||||
}
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::InsertBits(Register dest, Register source, Register pos,
|
||||
int size) {
|
||||
Ror(dest, dest, pos);
|
||||
Ins(dest, source, 0, size);
|
||||
{
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
Subu(scratch, pos, Operand(32));
|
||||
Neg(scratch, Operand(scratch));
|
||||
Ror(dest, dest, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Seb(Register rd, Register rt) {
|
||||
if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
|
||||
seb(rd, rt);
|
||||
|
@ -570,6 +570,10 @@ class TurboAssembler : public Assembler {
|
||||
// MIPS32 R2 instruction macro.
|
||||
void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
void ExtractBits(Register dest, Register source, Register pos, int size,
|
||||
bool sign_extend = false);
|
||||
void InsertBits(Register dest, Register source, Register pos, int size);
|
||||
|
||||
void Seb(Register rd, Register rt);
|
||||
void Seh(Register rd, Register rt);
|
||||
void Neg_s(FPURegister fd, FPURegister fs);
|
||||
@ -625,6 +629,9 @@ class TurboAssembler : public Assembler {
|
||||
void Ldc1(FPURegister fd, const MemOperand& src);
|
||||
void Sdc1(FPURegister fs, const MemOperand& dst);
|
||||
|
||||
void Ll(Register rd, const MemOperand& rs);
|
||||
void Sc(Register rd, const MemOperand& rs);
|
||||
|
||||
// Perform a floating-point min or max operation with the
|
||||
// (IEEE-754-compatible) semantics of MIPS32's Release 6 MIN.fmt/MAX.fmt.
|
||||
// Some cases, typically NaNs or +/-0.0, are expected to be rare and are
|
||||
|
@ -5662,6 +5662,19 @@ void Simulator::DecodeTypeImmediate() {
|
||||
WriteW(addr, mem_value, instr_.instr());
|
||||
break;
|
||||
}
|
||||
case LL: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(!IsMipsArchVariant(kMips32r6));
|
||||
set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
}
|
||||
case SC: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(!IsMipsArchVariant(kMips32r6));
|
||||
WriteW(rs + se_imm16, rt, instr_.instr());
|
||||
set_register(rt_reg, 1);
|
||||
break;
|
||||
}
|
||||
case LWC1:
|
||||
set_fpu_register_hi_word(ft_reg, 0);
|
||||
set_fpu_register_word(ft_reg,
|
||||
@ -5726,6 +5739,30 @@ void Simulator::DecodeTypeImmediate() {
|
||||
SetResult(rs_reg, alu_out);
|
||||
break;
|
||||
}
|
||||
case SPECIAL3: {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case LL_R6: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
int32_t base = get_register(instr_.BaseValue());
|
||||
int32_t offset9 = instr_.Imm9Value();
|
||||
set_register(rt_reg, ReadW(base + offset9, instr_.instr()));
|
||||
break;
|
||||
}
|
||||
case SC_R6: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
int32_t base = get_register(instr_.BaseValue());
|
||||
int32_t offset9 = instr_.Imm9Value();
|
||||
WriteW(base + offset9, rt, instr_.instr());
|
||||
set_register(rt_reg, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSA:
|
||||
switch (instr_.MSAMinorOpcodeField()) {
|
||||
case kMsaMinorI8:
|
||||
|
@ -1117,6 +1117,16 @@ void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
|
||||
emit(instr, is_compact_branch);
|
||||
}
|
||||
|
||||
void Assembler::GenInstrImmediate(Opcode opcode, Register base, Register rt,
|
||||
int32_t offset9, int bit6,
|
||||
SecondaryField func) {
|
||||
DCHECK(base.is_valid() && rt.is_valid() && is_int9(offset9) &&
|
||||
is_uint1(bit6));
|
||||
Instr instr = opcode | (base.code() << kBaseShift) | (rt.code() << kRtShift) |
|
||||
((offset9 << kImm9Shift) & kImm9Mask) | bit6 << kBit6Shift |
|
||||
func;
|
||||
emit(instr);
|
||||
}
|
||||
|
||||
void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
|
||||
int32_t j,
|
||||
@ -2305,6 +2315,47 @@ void Assembler::swr(Register rd, const MemOperand& rs) {
|
||||
GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
|
||||
void Assembler::ll(Register rd, const MemOperand& rs) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 0, LL_R6);
|
||||
} else {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
DCHECK(is_int16(rs.offset_));
|
||||
GenInstrImmediate(LL, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::lld(Register rd, const MemOperand& rs) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 0, LLD_R6);
|
||||
} else {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
DCHECK(is_int16(rs.offset_));
|
||||
GenInstrImmediate(LLD, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::sc(Register rd, const MemOperand& rs) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 0, SC_R6);
|
||||
} else {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
GenInstrImmediate(SC, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::scd(Register rd, const MemOperand& rs) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
DCHECK(is_int9(rs.offset_));
|
||||
GenInstrImmediate(SPECIAL3, rs.rm(), rd, rs.offset_, 0, SCD_R6);
|
||||
} else {
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
GenInstrImmediate(SCD, rs.rm(), rd, rs.offset_);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::lui(Register rd, int32_t j) {
|
||||
DCHECK(is_uint16(j));
|
||||
|
@ -1052,6 +1052,12 @@ class Assembler : public AssemblerBase {
|
||||
void ld(Register rd, const MemOperand& rs);
|
||||
void sd(Register rd, const MemOperand& rs);
|
||||
|
||||
// ----------Atomic instructions--------------
|
||||
|
||||
void ll(Register rd, const MemOperand& rs);
|
||||
void sc(Register rd, const MemOperand& rs);
|
||||
void lld(Register rd, const MemOperand& rs);
|
||||
void scd(Register rd, const MemOperand& rs);
|
||||
|
||||
// ---------PC-Relative-instructions-----------
|
||||
|
||||
@ -2231,6 +2237,8 @@ class Assembler : public AssemblerBase {
|
||||
void GenInstrImmediate(
|
||||
Opcode opcode, Register r1, FPURegister r2, int32_t j,
|
||||
CompactBranchType is_compact_branch = CompactBranchType::NO);
|
||||
void GenInstrImmediate(Opcode opcode, Register base, Register rt,
|
||||
int32_t offset9, int bit6, SecondaryField func);
|
||||
void GenInstrImmediate(
|
||||
Opcode opcode, Register rs, int32_t offset21,
|
||||
CompactBranchType is_compact_branch = CompactBranchType::NO);
|
||||
|
@ -276,7 +276,13 @@ const int kBp2Shift = 6;
|
||||
const int kBp2Bits = 2;
|
||||
const int kBp3Shift = 6;
|
||||
const int kBp3Bits = 3;
|
||||
const int kBaseShift = 21;
|
||||
const int kBaseBits = 5;
|
||||
const int kBit6Shift = 6;
|
||||
const int kBit6Bits = 1;
|
||||
|
||||
const int kImm9Shift = 7;
|
||||
const int kImm9Bits = 9;
|
||||
const int kImm16Shift = 0;
|
||||
const int kImm16Bits = 16;
|
||||
const int kImm18Shift = 0;
|
||||
@ -328,6 +334,7 @@ const int kWdShift = 6;
|
||||
// ----- Miscellaneous useful masks.
|
||||
// Instruction bit masks.
|
||||
const int kOpcodeMask = ((1 << kOpcodeBits) - 1) << kOpcodeShift;
|
||||
const int kImm9Mask = ((1 << kImm9Bits) - 1) << kImm9Shift;
|
||||
const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift;
|
||||
const int kImm18Mask = ((1 << kImm18Bits) - 1) << kImm18Shift;
|
||||
const int kImm19Mask = ((1 << kImm19Bits) - 1) << kImm19Shift;
|
||||
@ -421,6 +428,7 @@ enum Opcode : uint32_t {
|
||||
SDR = ((5U << 3) + 5) << kOpcodeShift,
|
||||
SWR = ((5U << 3) + 6) << kOpcodeShift,
|
||||
|
||||
LL = ((6U << 3) + 0) << kOpcodeShift,
|
||||
LWC1 = ((6U << 3) + 1) << kOpcodeShift,
|
||||
BC = ((6U << 3) + 2) << kOpcodeShift,
|
||||
LLD = ((6U << 3) + 4) << kOpcodeShift,
|
||||
@ -430,6 +438,7 @@ enum Opcode : uint32_t {
|
||||
|
||||
PREF = ((6U << 3) + 3) << kOpcodeShift,
|
||||
|
||||
SC = ((7U << 3) + 0) << kOpcodeShift,
|
||||
SWC1 = ((7U << 3) + 1) << kOpcodeShift,
|
||||
BALC = ((7U << 3) + 2) << kOpcodeShift,
|
||||
PCREL = ((7U << 3) + 3) << kOpcodeShift,
|
||||
@ -557,6 +566,10 @@ enum SecondaryField : uint32_t {
|
||||
|
||||
BSHFL = ((4U << 3) + 0),
|
||||
DBSHFL = ((4U << 3) + 4),
|
||||
SC_R6 = ((4U << 3) + 6),
|
||||
SCD_R6 = ((4U << 3) + 7),
|
||||
LL_R6 = ((6U << 3) + 6),
|
||||
LLD_R6 = ((6U << 3) + 7),
|
||||
|
||||
// SPECIAL3 Encoding of sa Field.
|
||||
BITSWAP = ((0U << 3) + 0),
|
||||
@ -1442,6 +1455,11 @@ class InstructionGetters : public T {
|
||||
return this->Bits(kRdShift + kRdBits - 1, kRdShift);
|
||||
}
|
||||
|
||||
inline int BaseValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kBaseShift + kBaseBits - 1, kBaseShift);
|
||||
}
|
||||
|
||||
inline int SaValue() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kRegisterType);
|
||||
return this->Bits(kSaShift + kSaBits - 1, kSaShift);
|
||||
@ -1567,6 +1585,11 @@ class InstructionGetters : public T {
|
||||
return this->Bits(bits - 1, 0);
|
||||
}
|
||||
|
||||
inline int32_t Imm9Value() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm9Shift + kImm9Bits - 1, kImm9Shift);
|
||||
}
|
||||
|
||||
inline int32_t Imm16Value() const {
|
||||
DCHECK(this->InstructionType() == InstructionBase::kImmediateType);
|
||||
return this->Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
|
||||
@ -1777,6 +1800,13 @@ InstructionBase::Type InstructionBase::InstructionType() const {
|
||||
return kUnsupported;
|
||||
}
|
||||
}
|
||||
case LL_R6:
|
||||
case LLD_R6:
|
||||
case SC_R6:
|
||||
case SCD_R6: {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
return kImmediateType;
|
||||
}
|
||||
case DBSHFL: {
|
||||
int sa = SaFieldRaw() >> kSaShift;
|
||||
switch (sa) {
|
||||
|
@ -88,6 +88,8 @@ class Decoder {
|
||||
void PrintCc(Instruction* instr);
|
||||
void PrintFunction(Instruction* instr);
|
||||
void PrintSecondaryField(Instruction* instr);
|
||||
void PrintUImm9(Instruction* instr);
|
||||
void PrintSImm9(Instruction* instr);
|
||||
void PrintUImm16(Instruction* instr);
|
||||
void PrintSImm16(Instruction* instr);
|
||||
void PrintXImm16(Instruction* instr);
|
||||
@ -143,6 +145,7 @@ class Decoder {
|
||||
|
||||
void DecodeTypeImmediateCOP1(Instruction* instr);
|
||||
void DecodeTypeImmediateREGIMM(Instruction* instr);
|
||||
void DecodeTypeImmediateSPECIAL3(Instruction* instr);
|
||||
void DecodeTypeImmediate(Instruction* instr);
|
||||
|
||||
void DecodeTypeJump(Instruction* instr);
|
||||
@ -332,6 +335,17 @@ void Decoder::PrintCc(Instruction* instr) {
|
||||
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "cc(%d)", cc);
|
||||
}
|
||||
|
||||
// Print 9-bit unsigned immediate value.
|
||||
void Decoder::PrintUImm9(Instruction* instr) {
|
||||
int32_t imm = instr->Imm9Value();
|
||||
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
|
||||
}
|
||||
|
||||
// Print 9-bit signed immediate value.
|
||||
void Decoder::PrintSImm9(Instruction* instr) {
|
||||
int32_t imm = ((instr->Imm9Value()) << 23) >> 23;
|
||||
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
|
||||
}
|
||||
|
||||
// Print 16-bit unsigned immediate value.
|
||||
void Decoder::PrintUImm16(Instruction* instr) {
|
||||
@ -925,6 +939,16 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm8"));
|
||||
PrintMsaImm8(instr);
|
||||
return 4;
|
||||
} else if (format[3] == '9') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm9"));
|
||||
if (format[4] == 'u') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm9u"));
|
||||
PrintUImm9(instr);
|
||||
} else if (format[4] == 's') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "imm9s"));
|
||||
PrintSImm9(instr);
|
||||
}
|
||||
return 5;
|
||||
} else if (format[3] == 'b') {
|
||||
DCHECK(STRING_STARTS_WITH(format, "immb"));
|
||||
PrintMsaImmBit(instr);
|
||||
@ -1940,6 +1964,44 @@ void Decoder::DecodeTypeImmediateREGIMM(Instruction* instr) {
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::DecodeTypeImmediateSPECIAL3(Instruction* instr) {
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case LL_R6: {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Format(instr, "ll 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LLD_R6: {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Format(instr, "lld 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SC_R6: {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Format(instr, "sc 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCD_R6: {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Format(instr, "scd 'rt, 'imm9s('rs)");
|
||||
} else {
|
||||
Unknown(instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
switch (instr->OpcodeFieldRaw()) {
|
||||
@ -2160,6 +2222,34 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
case SWR:
|
||||
Format(instr, "swr 'rt, 'imm16s('rs)");
|
||||
break;
|
||||
case LL:
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "ll 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case LLD:
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "lld 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case SC:
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "sc 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case SCD:
|
||||
if (kArchVariant == kMips64r6) {
|
||||
Unknown(instr);
|
||||
} else {
|
||||
Format(instr, "scd 'rt, 'imm16s('rs)");
|
||||
}
|
||||
break;
|
||||
case LWC1:
|
||||
Format(instr, "lwc1 'ft, 'imm16s('rs)");
|
||||
break;
|
||||
@ -2215,6 +2305,9 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPECIAL3:
|
||||
DecodeTypeImmediateSPECIAL3(instr);
|
||||
break;
|
||||
case MSA:
|
||||
switch (instr->MSAMinorOpcodeField()) {
|
||||
case kMsaMinorI8:
|
||||
|
@ -917,13 +917,7 @@ void TurboAssembler::Nor(Register rd, Register rs, const Operand& rt) {
|
||||
}
|
||||
|
||||
void TurboAssembler::Neg(Register rs, const Operand& rt) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
DCHECK(rt.is_reg());
|
||||
DCHECK(!scratch.is(rs));
|
||||
DCHECK(!scratch.is(rt.rm()));
|
||||
li(scratch, -1);
|
||||
xor_(rs, rt.rm(), scratch);
|
||||
dsubu(rs, zero_reg, rt.rm());
|
||||
}
|
||||
|
||||
void TurboAssembler::Slt(Register rd, Register rs, const Operand& rt) {
|
||||
@ -1437,6 +1431,62 @@ void TurboAssembler::Sdc1(FPURegister fs, const MemOperand& src) {
|
||||
sdc1(fs, tmp);
|
||||
}
|
||||
|
||||
void TurboAssembler::Ll(Register rd, const MemOperand& rs) {
|
||||
bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
|
||||
: is_int16(rs.offset());
|
||||
if (is_one_instruction) {
|
||||
ll(rd, rs);
|
||||
} else {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
li(scratch, rs.offset());
|
||||
daddu(scratch, scratch, rs.rm());
|
||||
ll(rd, MemOperand(scratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Lld(Register rd, const MemOperand& rs) {
|
||||
bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
|
||||
: is_int16(rs.offset());
|
||||
if (is_one_instruction) {
|
||||
lld(rd, rs);
|
||||
} else {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
li(scratch, rs.offset());
|
||||
daddu(scratch, scratch, rs.rm());
|
||||
lld(rd, MemOperand(scratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Sc(Register rd, const MemOperand& rs) {
|
||||
bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
|
||||
: is_int16(rs.offset());
|
||||
if (is_one_instruction) {
|
||||
sc(rd, rs);
|
||||
} else {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
li(scratch, rs.offset());
|
||||
daddu(scratch, scratch, rs.rm());
|
||||
sc(rd, MemOperand(scratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Scd(Register rd, const MemOperand& rs) {
|
||||
bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
|
||||
: is_int16(rs.offset());
|
||||
if (is_one_instruction) {
|
||||
scd(rd, rs);
|
||||
} else {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
li(scratch, rs.offset());
|
||||
daddu(scratch, scratch, rs.rm());
|
||||
scd(rd, MemOperand(scratch, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::li(Register dst, Handle<HeapObject> value, LiFlags mode) {
|
||||
li(dst, Operand(value), mode);
|
||||
}
|
||||
@ -1904,6 +1954,41 @@ void TurboAssembler::Dins(Register rt, Register rs, uint16_t pos,
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::ExtractBits(Register dest, Register source, Register pos,
|
||||
int size, bool sign_extend) {
|
||||
srav(dest, source, pos);
|
||||
Dext(dest, dest, 0, size);
|
||||
if (sign_extend) {
|
||||
switch (size) {
|
||||
case 8:
|
||||
seb(dest, dest);
|
||||
break;
|
||||
case 16:
|
||||
seh(dest, dest);
|
||||
break;
|
||||
case 32:
|
||||
// sign-extend word
|
||||
sll(dest, dest, 0);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::InsertBits(Register dest, Register source, Register pos,
|
||||
int size) {
|
||||
Ror(dest, dest, pos);
|
||||
Dins(dest, source, 0, size);
|
||||
{
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
Dsubu(scratch, pos, Operand(64));
|
||||
Neg(scratch, Operand(scratch));
|
||||
Ror(dest, dest, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Neg_s(FPURegister fd, FPURegister fs) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
// r6 neg_s changes the sign for NaN-like operands as well.
|
||||
|
@ -589,6 +589,9 @@ class TurboAssembler : public Assembler {
|
||||
void Dext(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
void Dins(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
void ExtractBits(Register dest, Register source, Register pos, int size,
|
||||
bool sign_extend = false);
|
||||
void InsertBits(Register dest, Register source, Register pos, int size);
|
||||
void Neg_s(FPURegister fd, FPURegister fs);
|
||||
void Neg_d(FPURegister fd, FPURegister fs);
|
||||
|
||||
@ -639,6 +642,12 @@ class TurboAssembler : public Assembler {
|
||||
void Ldc1(FPURegister fd, const MemOperand& src);
|
||||
void Sdc1(FPURegister fs, const MemOperand& dst);
|
||||
|
||||
void Ll(Register rd, const MemOperand& rs);
|
||||
void Sc(Register rd, const MemOperand& rs);
|
||||
|
||||
void Lld(Register rd, const MemOperand& rs);
|
||||
void Scd(Register rd, const MemOperand& rs);
|
||||
|
||||
// Perform a floating-point min or max operation with the
|
||||
// (IEEE-754-compatible) semantics of MIPS32's Release 6 MIN.fmt/MAX.fmt.
|
||||
// Some cases, typically NaNs or +/-0.0, are expected to be rare and are
|
||||
|
@ -5963,6 +5963,32 @@ void Simulator::DecodeTypeImmediate() {
|
||||
Write2W(addr, mem_value, instr_.instr());
|
||||
break;
|
||||
}
|
||||
case LL: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
}
|
||||
case SC: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr_.instr());
|
||||
set_register(rt_reg, 1);
|
||||
break;
|
||||
}
|
||||
case LLD: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
set_register(rt_reg, ReadD(rs + se_imm16, instr_.instr()));
|
||||
break;
|
||||
}
|
||||
case SCD: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r2);
|
||||
WriteD(rs + se_imm16, rt, instr_.instr());
|
||||
set_register(rt_reg, 1);
|
||||
break;
|
||||
}
|
||||
case LWC1:
|
||||
set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits.
|
||||
set_fpu_register_word(ft_reg,
|
||||
@ -6046,6 +6072,48 @@ void Simulator::DecodeTypeImmediate() {
|
||||
SetResult(rs_reg, alu_out);
|
||||
break;
|
||||
}
|
||||
case SPECIAL3: {
|
||||
switch (instr_.FunctionFieldRaw()) {
|
||||
case LL_R6: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
int64_t base = get_register(instr_.BaseValue());
|
||||
int32_t offset9 = instr_.Imm9Value();
|
||||
set_register(rt_reg, ReadW(base + offset9, instr_.instr()));
|
||||
break;
|
||||
}
|
||||
case LLD_R6: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
int64_t base = get_register(instr_.BaseValue());
|
||||
int32_t offset9 = instr_.Imm9Value();
|
||||
set_register(rt_reg, ReadD(base + offset9, instr_.instr()));
|
||||
break;
|
||||
}
|
||||
case SC_R6: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
int64_t base = get_register(instr_.BaseValue());
|
||||
int32_t offset9 = instr_.Imm9Value();
|
||||
WriteW(base + offset9, static_cast<int32_t>(rt), instr_.instr());
|
||||
set_register(rt_reg, 1);
|
||||
break;
|
||||
}
|
||||
case SCD_R6: {
|
||||
// LL/SC sequence cannot be simulated properly
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
int64_t base = get_register(instr_.BaseValue());
|
||||
int32_t offset9 = instr_.Imm9Value();
|
||||
WriteD(base + offset9, rt, instr_.instr());
|
||||
set_register(rt_reg, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MSA:
|
||||
switch (instr_.MSAMinorOpcodeField()) {
|
||||
case kMsaMinorI8:
|
||||
|
@ -1121,6 +1121,18 @@ TEST(madd_msub_maddf_msubf) {
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
||||
TEST(atomic_load_store) {
|
||||
SET_UP();
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "7c62ffb6 ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "7c6200a6 sc v0, 1(v1)");
|
||||
} else {
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "c062ffff ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "e0620001 sc v0, 1(v1)");
|
||||
}
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
||||
TEST(MSA_BRANCH) {
|
||||
SET_UP();
|
||||
if (IsMipsArchVariant(kMips32r6) && CpuFeatures::IsSupported(MIPS_SIMD)) {
|
||||
|
@ -1316,6 +1316,22 @@ TEST(madd_msub_maddf_msubf) {
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
||||
TEST(atomic_load_store) {
|
||||
SET_UP();
|
||||
if (kArchVariant == kMips64r6) {
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "7c62ffb6 ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "7c6200a6 sc v0, 1(v1)");
|
||||
COMPARE(lld(v0, MemOperand(v1, -1)), "7c62ffb7 lld v0, -1(v1)");
|
||||
COMPARE(scd(v0, MemOperand(v1, 1)), "7c6200a7 scd v0, 1(v1)");
|
||||
} else {
|
||||
COMPARE(ll(v0, MemOperand(v1, -1)), "c062ffff ll v0, -1(v1)");
|
||||
COMPARE(sc(v0, MemOperand(v1, 1)), "e0620001 sc v0, 1(v1)");
|
||||
COMPARE(lld(v0, MemOperand(v1, -1)), "d062ffff lld v0, -1(v1)");
|
||||
COMPARE(scd(v0, MemOperand(v1, 1)), "f0620001 scd v0, 1(v1)");
|
||||
}
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
||||
TEST(MSA_BRANCH) {
|
||||
SET_UP();
|
||||
if ((kArchVariant == kMips64r6) && CpuFeatures::IsSupported(MIPS_SIMD)) {
|
||||
|
Loading…
Reference in New Issue
Block a user