MIPS: [turbofan] Add checked load/store operators.
authorpaul.lind <paul.lind@imgtec.com>
Wed, 3 Dec 2014 00:28:07 +0000 (16:28 -0800)
committerCommit bot <commit-bot@chromium.org>
Wed, 3 Dec 2014 00:28:24 +0000 (00:28 +0000)
Port c516d4f09408879602520748333754d3866224fb

Partial port to un-break the build. There are a few failing
tests, and the code is suboptimal for smaller offsets.

Fixes and mips64 port will come in another CL.

BUG=

Review URL: https://codereview.chromium.org/762853004

Cr-Commit-Position: refs/heads/master@{#25626}

src/compiler/mips/code-generator-mips.cc
src/compiler/mips/instruction-selector-mips.cc
src/mips/code-stubs-mips.cc
src/mips/codegen-mips.cc
src/mips/macro-assembler-mips.cc
src/mips/macro-assembler-mips.h

index 6fb0a30edd41a2261f73140a882eda1e376af8e2..1b004e51e3f24f4782a5e8d227b842b59e2586bc 100644 (file)
@@ -102,10 +102,7 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
     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);
@@ -124,6 +121,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))); \
+    __ 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);
@@ -373,7 +462,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* 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);
@@ -384,6 +473,43 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       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;
   }
 }
 
@@ -805,14 +931,13 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
       }
       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());
index 4ee81a7486804efe72692542a32776562f997aaf..afa56da5a7424a0b366233aaac5def84087a9e4a 100644 (file)
@@ -483,6 +483,75 @@ void InstructionSelector::VisitCall(Node* node) {
 }
 
 
+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.
index cfc89d17ae34ea6c7d535950a58bda313d51d972..1ef6af9a999d391821df1d878595592561ec7c38 100644 (file)
@@ -882,7 +882,7 @@ void MathPowStub::Generate(MacroAssembler* masm) {
 
       // Add +0 to convert -0 to +0.
       __ add_d(double_scratch, double_base, kDoubleRegZero);
-      __ Move(double_result, 1);
+      __ Move(double_result, 1.);
       __ sqrt_d(double_scratch, double_scratch);
       __ div_d(double_result, double_result, double_scratch);
       __ jmp(&done);
index 599aace2ee67a2879b39d62f9f3eee91f3e48c7b..fbd40443168187157c128fd17c5f92be12d08b1a 100644 (file)
@@ -1145,7 +1145,7 @@ void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
   // Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
   DCHECK(*reinterpret_cast<double*>
          (ExternalReference::math_exp_constants(8).address()) == 1);
-  __ Move(double_scratch2, 1);
+  __ Move(double_scratch2, 1.);
   __ add_d(result, result, double_scratch2);
   __ srl(temp1, temp2, 11);
   __ Ext(temp2, temp2, 0, 11);
index b2f60c5d2a09749cdedcbb862495d6ac1c01c3db..c290f8b3449a500788eb9947b5b2d62de68cdae9 100644 (file)
@@ -1549,6 +1549,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) {
   static const DoubleRepresentation minus_zero(-0.0);
   static const DoubleRepresentation zero(0.0);
index 98f510b435ec1848d6cb850996dca4e0678e4e9e..d7f357016df167d5f5d5ee3b4c83ae7ebb4ad560 100644 (file)
@@ -250,8 +250,10 @@ class MacroAssembler: public Assembler {
     Mthc1(src_high, dst);
   }
 
-  // Conditional move.
+  void Move(FPURegister dst, float imm);
   void Move(FPURegister dst, double imm);
+
+  // Conditional move.
   void Movz(Register rd, Register rs, Register rt);
   void Movn(Register rd, Register rs, Register rt);
   void Movt(Register rd, Register rs, uint16_t cc = 0);