return MemOperand(no_reg);
}
- MemOperand MemoryOperand() {
- int index = 0;
- return MemoryOperand(&index);
- }
+ MemOperand MemoryOperand(int index = 0) { return MemoryOperand(&index); }
MemOperand ToMemOperand(InstructionOperand* op) const {
DCHECK(op != NULL);
}
+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))); \
+ __ addu(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))); \
+ __ addu(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); \
+ __ addu(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); \
+ __ addu(at, i.InputRegister(3), offset); \
+ __ asm_instr(value, MemOperand(at, 0)); \
+ __ bind(&done); \
+ } while (0)
+
+
// Assembles an instruction after register allocation, producing machine code.
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
MipsOperandConverter i(this, instr);
case kMipsPush:
__ Push(i.InputRegister(0));
break;
- case kMipsStoreWriteBarrier:
+ case kMipsStoreWriteBarrier: {
Register object = i.InputRegister(0);
Register index = i.InputRegister(1);
Register value = i.InputRegister(2);
RAStatus ra_status = kRAHasNotBeenSaved;
__ RecordWrite(object, index, value, ra_status, mode);
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;
}
}
}
if (destination->IsStackSlot()) __ sw(dst, g.ToMemOperand(destination));
} 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()) {
- __ 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 {
DCHECK_EQ(Constant::kFloat64, src.type());
}
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+ MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+ MachineType typ = TypeOf(OpParameter<MachineType>(node));
+ MipsOperandGenerator 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));
+ MipsOperandGenerator 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 {
// Shared routine for multiple compare operations.