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:
Ivica Bogosavljevic 2017-08-15 16:30:16 +02:00 committed by Commit Bot
parent 8ee068388e
commit 89ac7fcdb4
20 changed files with 828 additions and 78 deletions

View File

@ -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(),

View File

@ -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();

View File

@ -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)));

View File

@ -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();

View File

@ -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));

View File

@ -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);

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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:

View File

@ -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));

View File

@ -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);

View File

@ -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) {

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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:

View File

@ -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)) {

View File

@ -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)) {