MIPS64: [turbofan] Add checked load/store operators.
Port c516d4f094
BUG=
Review URL: https://codereview.chromium.org/773113005
Cr-Commit-Position: refs/heads/master@{#25641}
This commit is contained in:
parent
d67e573dbe
commit
68c800ef9d
@ -103,10 +103,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
|
|||||||
return MemOperand(no_reg);
|
return MemOperand(no_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemOperand MemoryOperand() {
|
MemOperand MemoryOperand(int index = 0) { return MemoryOperand(&index); }
|
||||||
int index = 0;
|
|
||||||
return MemoryOperand(&index);
|
|
||||||
}
|
|
||||||
|
|
||||||
MemOperand ToMemOperand(InstructionOperand* op) const {
|
MemOperand ToMemOperand(InstructionOperand* op) const {
|
||||||
DCHECK(op != NULL);
|
DCHECK(op != NULL);
|
||||||
@ -125,6 +122,98 @@ static inline bool HasRegisterInput(Instruction* instr, int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class OutOfLineLoadSingle FINAL : public OutOfLineCode {
|
||||||
|
public:
|
||||||
|
OutOfLineLoadSingle(CodeGenerator* gen, FloatRegister result)
|
||||||
|
: OutOfLineCode(gen), result_(result) {}
|
||||||
|
|
||||||
|
void Generate() FINAL {
|
||||||
|
__ Move(result_, std::numeric_limits<float>::quiet_NaN());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FloatRegister const result_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OutOfLineLoadDouble FINAL : public OutOfLineCode {
|
||||||
|
public:
|
||||||
|
OutOfLineLoadDouble(CodeGenerator* gen, DoubleRegister result)
|
||||||
|
: OutOfLineCode(gen), result_(result) {}
|
||||||
|
|
||||||
|
void Generate() FINAL {
|
||||||
|
__ Move(result_, std::numeric_limits<double>::quiet_NaN());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DoubleRegister const result_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OutOfLineLoadInteger FINAL : public OutOfLineCode {
|
||||||
|
public:
|
||||||
|
OutOfLineLoadInteger(CodeGenerator* gen, Register result)
|
||||||
|
: OutOfLineCode(gen), result_(result) {}
|
||||||
|
|
||||||
|
void Generate() FINAL { __ mov(result_, zero_reg); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Register const result_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
#define ASSEMBLE_CHECKED_LOAD_FLOAT(width, asm_instr) \
|
||||||
|
do { \
|
||||||
|
auto result = i.Output##width##Register(); \
|
||||||
|
auto offset = i.InputRegister(0); \
|
||||||
|
auto ool = new (zone()) OutOfLineLoad##width(this, result); \
|
||||||
|
__ Branch(ool->entry(), hs, offset, Operand(i.InputRegister(1))); \
|
||||||
|
__ Daddu(at, i.InputRegister(2), offset); \
|
||||||
|
__ asm_instr(result, MemOperand(at, 0)); \
|
||||||
|
__ bind(ool->exit()); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
|
||||||
|
do { \
|
||||||
|
auto result = i.OutputRegister(); \
|
||||||
|
auto offset = i.InputRegister(0); \
|
||||||
|
auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
|
||||||
|
__ Branch(ool->entry(), hs, offset, Operand(i.InputRegister(1))); \
|
||||||
|
__ Daddu(at, i.InputRegister(2), offset); \
|
||||||
|
__ asm_instr(result, MemOperand(at, 0)); \
|
||||||
|
__ bind(ool->exit()); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#define ASSEMBLE_CHECKED_STORE_FLOAT(width, asm_instr) \
|
||||||
|
do { \
|
||||||
|
auto offset = i.InputRegister(0); \
|
||||||
|
Label done; \
|
||||||
|
__ Branch(&done, hs, offset, Operand(i.InputRegister(1))); \
|
||||||
|
auto value = i.Input##width##Register(2); \
|
||||||
|
__ Daddu(at, i.InputRegister(3), offset); \
|
||||||
|
__ asm_instr(value, MemOperand(at, 0)); \
|
||||||
|
__ bind(&done); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
|
||||||
|
do { \
|
||||||
|
auto offset = i.InputRegister(0); \
|
||||||
|
Label done; \
|
||||||
|
__ Branch(&done, hs, offset, Operand(i.InputRegister(1))); \
|
||||||
|
auto value = i.InputRegister(2); \
|
||||||
|
__ Daddu(at, i.InputRegister(3), offset); \
|
||||||
|
__ asm_instr(value, MemOperand(at, 0)); \
|
||||||
|
__ bind(&done); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
// Assembles an instruction after register allocation, producing machine code.
|
// Assembles an instruction after register allocation, producing machine code.
|
||||||
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||||
MipsOperandConverter i(this, instr);
|
MipsOperandConverter i(this, instr);
|
||||||
@ -469,7 +558,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
__ sd(i.InputRegister(0), MemOperand(sp, slot << kPointerSizeLog2));
|
__ sd(i.InputRegister(0), MemOperand(sp, slot << kPointerSizeLog2));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kMips64StoreWriteBarrier:
|
case kMips64StoreWriteBarrier: {
|
||||||
Register object = i.InputRegister(0);
|
Register object = i.InputRegister(0);
|
||||||
Register index = i.InputRegister(1);
|
Register index = i.InputRegister(1);
|
||||||
Register value = i.InputRegister(2);
|
Register value = i.InputRegister(2);
|
||||||
@ -480,6 +569,43 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
RAStatus ra_status = kRAHasNotBeenSaved;
|
RAStatus ra_status = kRAHasNotBeenSaved;
|
||||||
__ RecordWrite(object, index, value, ra_status, mode);
|
__ RecordWrite(object, index, value, ra_status, mode);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case kCheckedLoadInt8:
|
||||||
|
ASSEMBLE_CHECKED_LOAD_INTEGER(lb);
|
||||||
|
break;
|
||||||
|
case kCheckedLoadUint8:
|
||||||
|
ASSEMBLE_CHECKED_LOAD_INTEGER(lbu);
|
||||||
|
break;
|
||||||
|
case kCheckedLoadInt16:
|
||||||
|
ASSEMBLE_CHECKED_LOAD_INTEGER(lh);
|
||||||
|
break;
|
||||||
|
case kCheckedLoadUint16:
|
||||||
|
ASSEMBLE_CHECKED_LOAD_INTEGER(lhu);
|
||||||
|
break;
|
||||||
|
case kCheckedLoadWord32:
|
||||||
|
ASSEMBLE_CHECKED_LOAD_INTEGER(lw);
|
||||||
|
break;
|
||||||
|
case kCheckedLoadFloat32:
|
||||||
|
ASSEMBLE_CHECKED_LOAD_FLOAT(Single, lwc1);
|
||||||
|
break;
|
||||||
|
case kCheckedLoadFloat64:
|
||||||
|
ASSEMBLE_CHECKED_LOAD_FLOAT(Double, ldc1);
|
||||||
|
break;
|
||||||
|
case kCheckedStoreWord8:
|
||||||
|
ASSEMBLE_CHECKED_STORE_INTEGER(sb);
|
||||||
|
break;
|
||||||
|
case kCheckedStoreWord16:
|
||||||
|
ASSEMBLE_CHECKED_STORE_INTEGER(sh);
|
||||||
|
break;
|
||||||
|
case kCheckedStoreWord32:
|
||||||
|
ASSEMBLE_CHECKED_STORE_INTEGER(sw);
|
||||||
|
break;
|
||||||
|
case kCheckedStoreFloat32:
|
||||||
|
ASSEMBLE_CHECKED_STORE_FLOAT(Single, swc1);
|
||||||
|
break;
|
||||||
|
case kCheckedStoreFloat64:
|
||||||
|
ASSEMBLE_CHECKED_STORE_FLOAT(Double, sdc1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1090,14 +1216,13 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
|||||||
}
|
}
|
||||||
if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
|
if (destination->IsStackSlot()) __ sd(dst, g.ToMemOperand(destination));
|
||||||
} else if (src.type() == Constant::kFloat32) {
|
} else if (src.type() == Constant::kFloat32) {
|
||||||
FPURegister dst = destination->IsDoubleRegister()
|
|
||||||
? g.ToDoubleRegister(destination)
|
|
||||||
: kScratchDoubleReg.low();
|
|
||||||
// TODO(turbofan): Can we do better here?
|
|
||||||
__ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
|
|
||||||
__ mtc1(at, dst);
|
|
||||||
if (destination->IsDoubleStackSlot()) {
|
if (destination->IsDoubleStackSlot()) {
|
||||||
__ swc1(dst, g.ToMemOperand(destination));
|
MemOperand dst = g.ToMemOperand(destination);
|
||||||
|
__ li(at, Operand(bit_cast<int32_t>(src.ToFloat32())));
|
||||||
|
__ sw(at, dst);
|
||||||
|
} else {
|
||||||
|
FloatRegister dst = g.ToSingleRegister(destination);
|
||||||
|
__ Move(dst, src.ToFloat32());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DCHECK_EQ(Constant::kFloat64, src.type());
|
DCHECK_EQ(Constant::kFloat64, src.type());
|
||||||
|
@ -680,6 +680,75 @@ void InstructionSelector::VisitCall(Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitCheckedLoad(Node* node) {
|
||||||
|
MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
|
||||||
|
MachineType typ = TypeOf(OpParameter<MachineType>(node));
|
||||||
|
Mips64OperandGenerator g(this);
|
||||||
|
Node* const buffer = node->InputAt(0);
|
||||||
|
Node* const offset = node->InputAt(1);
|
||||||
|
Node* const length = node->InputAt(2);
|
||||||
|
ArchOpcode opcode;
|
||||||
|
switch (rep) {
|
||||||
|
case kRepWord8:
|
||||||
|
opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
|
||||||
|
break;
|
||||||
|
case kRepWord16:
|
||||||
|
opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
|
||||||
|
break;
|
||||||
|
case kRepWord32:
|
||||||
|
opcode = kCheckedLoadWord32;
|
||||||
|
break;
|
||||||
|
case kRepFloat32:
|
||||||
|
opcode = kCheckedLoadFloat32;
|
||||||
|
break;
|
||||||
|
case kRepFloat64:
|
||||||
|
opcode = kCheckedLoadFloat64;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InstructionOperand* offset_operand = g.UseRegister(offset);
|
||||||
|
Emit(opcode | AddressingModeField::encode(kMode_MRI),
|
||||||
|
g.DefineAsRegister(node), offset_operand, g.UseRegister(length),
|
||||||
|
g.UseRegister(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InstructionSelector::VisitCheckedStore(Node* node) {
|
||||||
|
MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
|
||||||
|
Mips64OperandGenerator g(this);
|
||||||
|
Node* const buffer = node->InputAt(0);
|
||||||
|
Node* const offset = node->InputAt(1);
|
||||||
|
Node* const length = node->InputAt(2);
|
||||||
|
Node* const value = node->InputAt(3);
|
||||||
|
ArchOpcode opcode;
|
||||||
|
switch (rep) {
|
||||||
|
case kRepWord8:
|
||||||
|
opcode = kCheckedStoreWord8;
|
||||||
|
break;
|
||||||
|
case kRepWord16:
|
||||||
|
opcode = kCheckedStoreWord16;
|
||||||
|
break;
|
||||||
|
case kRepWord32:
|
||||||
|
opcode = kCheckedStoreWord32;
|
||||||
|
break;
|
||||||
|
case kRepFloat32:
|
||||||
|
opcode = kCheckedStoreFloat32;
|
||||||
|
break;
|
||||||
|
case kRepFloat64:
|
||||||
|
opcode = kCheckedStoreFloat64;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InstructionOperand* offset_operand = g.UseRegister(offset);
|
||||||
|
Emit(opcode | AddressingModeField::encode(kMode_MRI), nullptr, offset_operand,
|
||||||
|
g.UseRegister(length), g.UseRegister(value), g.UseRegister(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Shared routine for multiple compare operations.
|
// Shared routine for multiple compare operations.
|
||||||
|
@ -851,7 +851,7 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
// double_scratch can be overwritten in the delay slot.
|
// double_scratch can be overwritten in the delay slot.
|
||||||
// Calculates square root of base. Check for the special case of
|
// Calculates square root of base. Check for the special case of
|
||||||
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
|
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
|
||||||
__ Move(double_scratch, -V8_INFINITY);
|
__ Move(double_scratch, static_cast<double>(-V8_INFINITY));
|
||||||
__ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
|
__ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
|
||||||
__ neg_d(double_result, double_scratch);
|
__ neg_d(double_result, double_scratch);
|
||||||
|
|
||||||
@ -871,13 +871,13 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
// double_scratch can be overwritten in the delay slot.
|
// double_scratch can be overwritten in the delay slot.
|
||||||
// Calculates square root of base. Check for the special case of
|
// Calculates square root of base. Check for the special case of
|
||||||
// Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
|
// Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
|
||||||
__ Move(double_scratch, -V8_INFINITY);
|
__ Move(double_scratch, static_cast<double>(-V8_INFINITY));
|
||||||
__ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
|
__ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
|
||||||
__ Move(double_result, kDoubleRegZero);
|
__ Move(double_result, kDoubleRegZero);
|
||||||
|
|
||||||
// Add +0 to convert -0 to +0.
|
// Add +0 to convert -0 to +0.
|
||||||
__ add_d(double_scratch, double_base, kDoubleRegZero);
|
__ add_d(double_scratch, double_base, kDoubleRegZero);
|
||||||
__ Move(double_result, 1);
|
__ Move(double_result, 1.);
|
||||||
__ sqrt_d(double_scratch, double_scratch);
|
__ sqrt_d(double_scratch, double_scratch);
|
||||||
__ div_d(double_result, double_result, double_scratch);
|
__ div_d(double_result, double_result, double_scratch);
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
@ -1033,7 +1033,7 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
|
|||||||
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
|
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
|
||||||
DCHECK(*reinterpret_cast<double*>
|
DCHECK(*reinterpret_cast<double*>
|
||||||
(ExternalReference::math_exp_constants(8).address()) == 1);
|
(ExternalReference::math_exp_constants(8).address()) == 1);
|
||||||
__ Move(double_scratch2, 1);
|
__ Move(double_scratch2, 1.);
|
||||||
__ add_d(result, result, double_scratch2);
|
__ add_d(result, result, double_scratch2);
|
||||||
__ dsrl(temp1, temp2, 11);
|
__ dsrl(temp1, temp2, 11);
|
||||||
__ Ext(temp2, temp2, 0, 11);
|
__ Ext(temp2, temp2, 0, 11);
|
||||||
|
@ -3869,7 +3869,7 @@ void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
|
|||||||
// Math.pow(-Infinity, 0.5) == Infinity
|
// Math.pow(-Infinity, 0.5) == Infinity
|
||||||
// Math.sqrt(-Infinity) == NaN
|
// Math.sqrt(-Infinity) == NaN
|
||||||
Label done;
|
Label done;
|
||||||
__ Move(temp, -V8_INFINITY);
|
__ Move(temp, static_cast<double>(-V8_INFINITY));
|
||||||
__ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
|
__ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
|
||||||
// Set up Infinity in the delay slot.
|
// Set up Infinity in the delay slot.
|
||||||
// result is overwritten if the branch is not taken.
|
// result is overwritten if the branch is not taken.
|
||||||
|
@ -1717,6 +1717,12 @@ void MacroAssembler::BranchF(Label* target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroAssembler::Move(FPURegister dst, float imm) {
|
||||||
|
li(at, Operand(bit_cast<int32_t>(imm)));
|
||||||
|
mtc1(at, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::Move(FPURegister dst, double imm) {
|
void MacroAssembler::Move(FPURegister dst, double imm) {
|
||||||
static const DoubleRepresentation minus_zero(-0.0);
|
static const DoubleRepresentation minus_zero(-0.0);
|
||||||
static const DoubleRepresentation zero(0.0);
|
static const DoubleRepresentation zero(0.0);
|
||||||
|
@ -271,8 +271,10 @@ class MacroAssembler: public Assembler {
|
|||||||
mthc1(src_high, dst);
|
mthc1(src_high, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conditional move.
|
void Move(FPURegister dst, float imm);
|
||||||
void Move(FPURegister dst, double imm);
|
void Move(FPURegister dst, double imm);
|
||||||
|
|
||||||
|
// Conditional move.
|
||||||
void Movz(Register rd, Register rs, Register rt);
|
void Movz(Register rd, Register rs, Register rt);
|
||||||
void Movn(Register rd, Register rs, Register rt);
|
void Movn(Register rd, Register rs, Register rt);
|
||||||
void Movt(Register rd, Register rs, uint16_t cc = 0);
|
void Movt(Register rd, Register rs, uint16_t cc = 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user