[turbofan] Support for %_DoubleHi, %_DoubleLo and %_ConstructDouble.
authorbmeurer <bmeurer@chromium.org>
Thu, 5 Mar 2015 09:22:26 +0000 (01:22 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 5 Mar 2015 09:22:38 +0000 (09:22 +0000)
This adds support for the double bits intrinsics to TurboFan, and is
a first step towards fast Math functions inlined into TurboFan code
or even compiled by themselves with TurboFan.

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

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

45 files changed:
src/compiler/arm/code-generator-arm.cc
src/compiler/arm/instruction-codes-arm.h
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/code-generator-arm64.cc
src/compiler/arm64/instruction-codes-arm64.h
src/compiler/arm64/instruction-selector-arm64.cc
src/compiler/ia32/code-generator-ia32.cc
src/compiler/ia32/instruction-codes-ia32.h
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/instruction-selector.cc
src/compiler/js-intrinsic-lowering.cc
src/compiler/js-intrinsic-lowering.h
src/compiler/machine-operator-reducer.cc
src/compiler/machine-operator-reducer.h
src/compiler/machine-operator.cc
src/compiler/machine-operator.h
src/compiler/opcodes.h
src/compiler/raw-machine-assembler.h
src/compiler/simplified-lowering.cc
src/compiler/typer.cc
src/compiler/verifier.cc
src/compiler/x64/code-generator-x64.cc
src/compiler/x64/instruction-codes-x64.h
src/compiler/x64/instruction-selector-x64.cc
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/disasm-ia32.cc
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
src/x64/disasm-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
test/cctest/compiler/test-run-machops.cc
test/cctest/test-disasm-ia32.cc
test/cctest/test-disasm-x64.cc
test/mjsunit/asm/construct-double.js [new file with mode: 0644]
test/mjsunit/asm/double-hi.js [new file with mode: 0644]
test/mjsunit/asm/double-lo.js [new file with mode: 0644]
test/unittests/compiler/js-intrinsic-lowering-unittest.cc
test/unittests/compiler/machine-operator-reducer-unittest.cc
test/unittests/compiler/machine-operator-unittest.cc
test/unittests/compiler/node-test-utils.cc
test/unittests/compiler/node-test-utils.h

index f47eafebf51a1cc84ae9fa5cf29079330c99b3ac..7f761640b21de4ed8ffd590f1e5001a34c150441 100644 (file)
@@ -617,6 +617,27 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArmVmovLowU32F64:
+      __ VmovLow(i.OutputRegister(), i.InputFloat64Register(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovLowF64U32:
+      __ VmovLow(i.OutputFloat64Register(), i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovHighU32F64:
+      __ VmovHigh(i.OutputRegister(), i.InputFloat64Register(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovHighF64U32:
+      __ VmovHigh(i.OutputFloat64Register(), i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmovF64U32U32:
+      __ vmov(i.OutputFloat64Register(), i.InputRegister(0),
+              i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmLdrb:
       __ ldrb(i.OutputRegister(), i.InputOffset());
       DCHECK_EQ(LeaveCC, i.OutputSBit());
index ecd0b2d70b6aa56f262299eb7941d2af9ba002ac..6e9e1e59781902e72e02fd4c03333aed326b9109 100644 (file)
@@ -63,6 +63,11 @@ namespace compiler {
   V(ArmVcvtF64U32)                 \
   V(ArmVcvtS32F64)                 \
   V(ArmVcvtU32F64)                 \
+  V(ArmVmovLowU32F64)              \
+  V(ArmVmovLowF64U32)              \
+  V(ArmVmovHighU32F64)             \
+  V(ArmVmovHighF64U32)             \
+  V(ArmVmovF64U32U32)              \
   V(ArmVldrF32)                    \
   V(ArmVstrF32)                    \
   V(ArmVldrF64)                    \
index e08226d5f3e44eed89f623d0882c4cf487ef24f6..d16c3e7e3b11153ba1d4534c7b649166616b924c 100644 (file)
@@ -1394,6 +1394,52 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmVmovLowU32F64, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmVmovHighU32F64, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertHighWord32 &&
+      CanCover(node, left)) {
+    left = left->InputAt(1);
+    Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(right),
+         g.UseRegister(left));
+    return;
+  }
+  Emit(kArmVmovLowF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
+       g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  ArmOperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (left->opcode() == IrOpcode::kFloat64InsertLowWord32 &&
+      CanCover(node, left)) {
+    left = left->InputAt(1);
+    Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), g.UseRegister(left),
+         g.UseRegister(right));
+    return;
+  }
+  Emit(kArmVmovHighF64U32, g.DefineSameAsFirst(node), g.UseRegister(left),
+       g.UseRegister(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
index b3c7230807935956e4ad64ef3a763a9d94180d78..0f19cbddfff3c5fe5d51954818d80e6f89d0cef8 100644 (file)
@@ -693,6 +693,29 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Uint32ToFloat64:
       __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
       break;
+    case kArm64Float64ExtractLowWord32:
+      __ Fmov(i.OutputRegister32(), i.InputFloat32Register(0));
+      break;
+    case kArm64Float64ExtractHighWord32:
+      __ Fmov(i.OutputRegister(), i.InputFloat64Register(0));
+      __ Lsr(i.OutputRegister(), i.OutputRegister(), 32);
+      break;
+    case kArm64Float64InsertLowWord32: {
+      UseScratchRegisterScope scope(masm());
+      Register tmp = scope.AcquireX();
+      __ Fmov(tmp, i.InputFloat64Register(0));
+      __ Bfi(tmp, i.InputRegister(1), 0, 32);
+      __ Fmov(i.OutputFloat64Register(), tmp);
+      break;
+    }
+    case kArm64Float64InsertHighWord32: {
+      UseScratchRegisterScope scope(masm());
+      Register tmp = scope.AcquireX();
+      __ Fmov(tmp.W(), i.InputFloat32Register(0));
+      __ Bfi(tmp, i.InputRegister(1), 32, 32);
+      __ Fmov(i.OutputFloat64Register(), tmp);
+      break;
+    }
     case kArm64Ldrb:
       __ Ldrb(i.OutputRegister(), i.MemoryOperand());
       break;
index 863451f7c5dc5c496ae8ce9dcfd853b6baa7f658..bbac27873ce090acec0c9139270a5e8fc945fa23 100644 (file)
@@ -94,6 +94,10 @@ namespace compiler {
   V(Arm64Float64ToUint32)          \
   V(Arm64Int32ToFloat64)           \
   V(Arm64Uint32ToFloat64)          \
+  V(Arm64Float64ExtractLowWord32)  \
+  V(Arm64Float64ExtractHighWord32) \
+  V(Arm64Float64InsertLowWord32)   \
+  V(Arm64Float64InsertHighWord32)  \
   V(Arm64LdrS)                     \
   V(Arm64StrS)                     \
   V(Arm64LdrD)                     \
index 1a071cd2d872e1fdec67ad84d3fb50befc19e05f..a27bd88733ee56e9ce8cdcfa40a7d4af3e63d114 100644 (file)
@@ -1576,6 +1576,40 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Float64ExtractLowWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Float64ExtractHighWord32, g.DefineAsRegister(node),
+       g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  // TODO(arm64): Some AArch64 specialist should be able to improve this.
+  Arm64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kArm64Float64InsertLowWord32, g.DefineAsRegister(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  // TODO(arm64): Some AArch64 specialist should be able to improve this.
+  Arm64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kArm64Float64InsertHighWord32, g.DefineAsRegister(node),
+       g.UseRegister(left), g.UseRegister(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
index d86151e616ca740ed286327bcf82ba8c613042b1..fcea57f93e8b3d005fb92faa151dd66352aef23c 100644 (file)
@@ -24,8 +24,8 @@ class IA32OperandConverter : public InstructionOperandConverter {
   IA32OperandConverter(CodeGenerator* gen, Instruction* instr)
       : InstructionOperandConverter(gen, instr) {}
 
-  Operand InputOperand(size_t index) {
-    return ToOperand(instr_->InputAt(index));
+  Operand InputOperand(size_t index, int extra = 0) {
+    return ToOperand(instr_->InputAt(index), extra);
   }
 
   Immediate InputImmediate(size_t index) {
@@ -531,6 +531,29 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kSSEUint32ToFloat64:
       __ LoadUint32(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
+    case kSSEFloat64ExtractLowWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ mov(i.OutputRegister(), i.InputOperand(0));
+      } else {
+        __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
+      }
+      break;
+    case kSSEFloat64ExtractHighWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
+      } else {
+        __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
+      }
+      break;
+    case kSSEFloat64InsertLowWord32:
+      __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
+      break;
+    case kSSEFloat64InsertHighWord32:
+      __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
+      break;
+    case kSSEFloat64LoadLowWord32:
+      __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
+      break;
     case kAVXFloat64Add: {
       CpuFeatureScope avx_scope(masm(), AVX);
       __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
index ec9fd188fcd791d035901097c1a0f5d701236996..b5a5225adc562f9fc1bc95f7ba22b7fd81adb6b2 100644 (file)
@@ -46,6 +46,11 @@ namespace compiler {
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
   V(SSEUint32ToFloat64)            \
+  V(SSEFloat64ExtractLowWord32)    \
+  V(SSEFloat64ExtractHighWord32)   \
+  V(SSEFloat64InsertLowWord32)     \
+  V(SSEFloat64InsertHighWord32)    \
+  V(SSEFloat64LoadLowWord32)       \
   V(AVXFloat64Add)                 \
   V(AVXFloat64Sub)                 \
   V(AVXFloat64Mul)                 \
index 8a352e29972ce8d14c557641692c37785c4ea506..54184302c565db287a13f5e7f80e1ea46cc433fb 100644 (file)
@@ -1068,6 +1068,43 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Float64Matcher mleft(left);
+  if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
+    Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
+    return;
+  }
+  Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  IA32OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
index bffe6f76949f47bbaab4f1cdabec14efc917810f..97fa9214f668524e81cd937681923b7ea1a6c1f4 100644 (file)
@@ -699,6 +699,12 @@ MachineType InstructionSelector::GetMachineType(Node* node) {
     case IrOpcode::kFloat64LessThan:
     case IrOpcode::kFloat64LessThanOrEqual:
       return kMachBool;
+    case IrOpcode::kFloat64ExtractLowWord32:
+    case IrOpcode::kFloat64ExtractHighWord32:
+      return kMachInt32;
+    case IrOpcode::kFloat64InsertLowWord32:
+    case IrOpcode::kFloat64InsertHighWord32:
+      return kMachFloat64;
     default:
       V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
                node->opcode(), node->op()->mnemonic(), node->id());
@@ -903,6 +909,14 @@ void InstructionSelector::VisitNode(Node* node) {
       return MarkAsDouble(node), VisitFloat64RoundTruncate(node);
     case IrOpcode::kFloat64RoundTiesAway:
       return MarkAsDouble(node), VisitFloat64RoundTiesAway(node);
+    case IrOpcode::kFloat64ExtractLowWord32:
+      return VisitFloat64ExtractLowWord32(node);
+    case IrOpcode::kFloat64ExtractHighWord32:
+      return VisitFloat64ExtractHighWord32(node);
+    case IrOpcode::kFloat64InsertLowWord32:
+      return MarkAsDouble(node), VisitFloat64InsertLowWord32(node);
+    case IrOpcode::kFloat64InsertHighWord32:
+      return MarkAsDouble(node), VisitFloat64InsertHighWord32(node);
     case IrOpcode::kLoadStackPointer:
       return VisitLoadStackPointer(node);
     case IrOpcode::kCheckedLoad: {
index 87e74b73d95f619369456c62a42fd86d08eccb27..0d3b3e642e8d7b0d5ede5058e3ae99b2249218f8 100644 (file)
@@ -31,6 +31,12 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
       return ReduceInlineIsInstanceType(node, JS_ARRAY_TYPE);
     case Runtime::kInlineIsFunction:
       return ReduceInlineIsInstanceType(node, JS_FUNCTION_TYPE);
+    case Runtime::kInlineOptimizedConstructDouble:
+      return ReduceInlineOptimizedConstructDouble(node);
+    case Runtime::kInlineOptimizedDoubleLo:
+      return ReduceInlineOptimizedDoubleLo(node);
+    case Runtime::kInlineOptimizedDoubleHi:
+      return ReduceInlineOptimizedDoubleHi(node);
     case Runtime::kInlineIsRegExp:
       return ReduceInlineIsInstanceType(node, JS_REGEXP_TYPE);
     case Runtime::kInlineValueOf:
@@ -92,6 +98,30 @@ Reduction JSIntrinsicLowering::ReduceInlineIsNonNegativeSmi(Node* node) {
 }
 
 
+Reduction JSIntrinsicLowering::ReduceInlineOptimizedConstructDouble(
+    Node* node) {
+  Node* high = NodeProperties::GetValueInput(node, 0);
+  Node* low = NodeProperties::GetValueInput(node, 1);
+  Node* value =
+      graph()->NewNode(machine()->Float64InsertHighWord32(),
+                       graph()->NewNode(machine()->Float64InsertLowWord32(),
+                                        jsgraph()->Constant(0), low),
+                       high);
+  NodeProperties::ReplaceWithValue(node, value);
+  return Replace(value);
+}
+
+
+Reduction JSIntrinsicLowering::ReduceInlineOptimizedDoubleLo(Node* node) {
+  return Change(node, machine()->Float64ExtractLowWord32());
+}
+
+
+Reduction JSIntrinsicLowering::ReduceInlineOptimizedDoubleHi(Node* node) {
+  return Change(node, machine()->Float64ExtractHighWord32());
+}
+
+
 Reduction JSIntrinsicLowering::ReduceInlineIsInstanceType(
     Node* node, InstanceType instance_type) {
   // if (%_IsSmi(value)) {
index d19c0f612123b297f937f27d089f58c0420b600e..d728c273f63257784c387d46f977bc943b5d90b7 100644 (file)
@@ -31,6 +31,9 @@ class JSIntrinsicLowering FINAL : public Reducer {
   Reduction ReduceInlineIsSmi(Node* node);
   Reduction ReduceInlineIsNonNegativeSmi(Node* node);
   Reduction ReduceInlineIsInstanceType(Node* node, InstanceType instance_type);
+  Reduction ReduceInlineOptimizedConstructDouble(Node* node);
+  Reduction ReduceInlineOptimizedDoubleLo(Node* node);
+  Reduction ReduceInlineOptimizedDoubleHi(Node* node);
   Reduction ReduceInlineValueOf(Node* node);
 
   Reduction Change(Node* node, const Operator* op);
index 5630bc8ef0ffae22a16159996867e751e3ab3884..ba0b7a1893b1fa0f6ea1b126c5cf454c905a4fdd 100644 (file)
@@ -433,6 +433,10 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
       if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0));
       break;
     }
+    case IrOpcode::kFloat64InsertLowWord32:
+      return ReduceFloat64InsertLowWord32(node);
+    case IrOpcode::kFloat64InsertHighWord32:
+      return ReduceFloat64InsertHighWord32(node);
     case IrOpcode::kStore:
       return ReduceStore(node);
     default:
@@ -975,6 +979,32 @@ Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
 }
 
 
+Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) {
+  DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode());
+  Float64Matcher mlhs(node->InputAt(0));
+  Uint32Matcher mrhs(node->InputAt(1));
+  if (mlhs.HasValue() && mrhs.HasValue()) {
+    return ReplaceFloat64(bit_cast<double>(
+        (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF00000000)) |
+        mrhs.Value()));
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
+  DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
+  Float64Matcher mlhs(node->InputAt(0));
+  Uint32Matcher mrhs(node->InputAt(1));
+  if (mlhs.HasValue() && mrhs.HasValue()) {
+    return ReplaceFloat64(bit_cast<double>(
+        (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF)) |
+        (static_cast<uint64_t>(mrhs.Value()) << 32)));
+  }
+  return NoChange();
+}
+
+
 CommonOperatorBuilder* MachineOperatorReducer::common() const {
   return jsgraph()->common();
 }
index f7c3bd7cfde5b04f0eb81e8e80511f84ca101992..7c41f143e20a9709761e1c783c88c06bd862e131 100644 (file)
@@ -78,6 +78,8 @@ class MachineOperatorReducer FINAL : public Reducer {
   Reduction ReduceWord32Sar(Node* node);
   Reduction ReduceWord32And(Node* node);
   Reduction ReduceWord32Or(Node* node);
+  Reduction ReduceFloat64InsertLowWord32(Node* node);
+  Reduction ReduceFloat64InsertHighWord32(Node* node);
 
   Graph* graph() const;
   JSGraph* jsgraph() const { return jsgraph_; }
index 2522a8e15dba03740ffe9a5e1cd72ff00666511f..6122eb144086f01d9ab6969e39c6623f5cfc6589 100644 (file)
@@ -130,6 +130,10 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
   V(Float64Equal, Operator::kCommutative, 2, 0, 1)                            \
   V(Float64LessThan, Operator::kNoProperties, 2, 0, 1)                        \
   V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                 \
+  V(Float64ExtractLowWord32, Operator::kNoProperties, 1, 0, 1)                \
+  V(Float64ExtractHighWord32, Operator::kNoProperties, 1, 0, 1)               \
+  V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1)                 \
+  V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1)                \
   V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1)
 
 
index 42f313019f41152e8a88b57f6dbbeeb0ed6ba970..e92f3c64f6393f517b7514ff79f1c2a9a804254b 100644 (file)
@@ -177,6 +177,12 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   bool HasFloat64RoundTruncate() { return flags_ & kFloat64RoundTruncate; }
   bool HasFloat64RoundTiesAway() { return flags_ & kFloat64RoundTiesAway; }
 
+  // Floating point bit representation.
+  const Operator* Float64ExtractLowWord32();
+  const Operator* Float64ExtractHighWord32();
+  const Operator* Float64InsertLowWord32();
+  const Operator* Float64InsertHighWord32();
+
   // load [base + index]
   const Operator* Load(LoadRepresentation rep);
 
@@ -226,10 +232,10 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
 #undef PSEUDO_OP_LIST
 
  private:
-  Zone* zone_;
-  const MachineOperatorGlobalCache& cache_;
-  const MachineType word_;
-  const Flags flags_;
+  Zone* const zone_;
+  MachineOperatorGlobalCache const& cache_;
+  MachineType const word_;
+  Flags const flags_;
 
   DISALLOW_COPY_AND_ASSIGN(MachineOperatorBuilder);
 };
index 6e9e1fb8f90add1de5261fdc0e57b134d4c7d954..5343c2f1c285c02ac913e54e2bc3ae77955e0ce6 100644 (file)
   V(Float64Ceil)                \
   V(Float64RoundTruncate)       \
   V(Float64RoundTiesAway)       \
+  V(Float64ExtractLowWord32)    \
+  V(Float64ExtractHighWord32)   \
+  V(Float64InsertLowWord32)     \
+  V(Float64InsertHighWord32)    \
   V(LoadStackPointer)           \
   V(CheckedLoad)                \
   V(CheckedStore)
index 04b1dc6f57cebff7a001225a92e84c868abf70ec..693f2fc87b006ab1bb52e66e5b54be40809d28e1 100644 (file)
@@ -393,6 +393,20 @@ class RawMachineAssembler : public GraphBuilder {
     return NewNode(machine()->Float64RoundTiesAway(), a);
   }
 
+  // Float64 bit operations.
+  Node* Float64ExtractLowWord32(Node* a) {
+    return NewNode(machine()->Float64ExtractLowWord32(), a);
+  }
+  Node* Float64ExtractHighWord32(Node* a) {
+    return NewNode(machine()->Float64ExtractHighWord32(), a);
+  }
+  Node* Float64InsertLowWord32(Node* a, Node* b) {
+    return NewNode(machine()->Float64InsertLowWord32(), a, b);
+  }
+  Node* Float64InsertHighWord32(Node* a, Node* b) {
+    return NewNode(machine()->Float64InsertHighWord32(), a, b);
+  }
+
   // Parameters.
   Node* Parameter(size_t index);
 
index 9e0b45016686df1558db3c08a0fae267f82cd733..a757248a99e16c96191f257966f5f49849832326 100644 (file)
@@ -273,13 +273,19 @@ class RepresentationSelector {
     SetOutput(node, kMachAnyTagged);
   }
 
+  // Helper for binops of the R x L -> O variety.
+  void VisitBinop(Node* node, MachineTypeUnion left_use,
+                  MachineTypeUnion right_use, MachineTypeUnion output) {
+    DCHECK_EQ(2, node->InputCount());
+    ProcessInput(node, 0, left_use);
+    ProcessInput(node, 1, right_use);
+    SetOutput(node, output);
+  }
+
   // Helper for binops of the I x I -> O variety.
   void VisitBinop(Node* node, MachineTypeUnion input_use,
                   MachineTypeUnion output) {
-    DCHECK_EQ(2, node->InputCount());
-    ProcessInput(node, 0, input_use);
-    ProcessInput(node, 1, input_use);
-    SetOutput(node, output);
+    VisitBinop(node, input_use, input_use, output);
   }
 
   // Helper for unops of the I -> O variety.
@@ -1033,6 +1039,12 @@ class RepresentationSelector {
       case IrOpcode::kFloat64LessThan:
       case IrOpcode::kFloat64LessThanOrEqual:
         return VisitFloat64Cmp(node);
+      case IrOpcode::kFloat64ExtractLowWord32:
+      case IrOpcode::kFloat64ExtractHighWord32:
+        return VisitUnop(node, kMachFloat64, kMachInt32);
+      case IrOpcode::kFloat64InsertLowWord32:
+      case IrOpcode::kFloat64InsertHighWord32:
+        return VisitBinop(node, kMachFloat64, kMachInt32, kMachFloat64);
       case IrOpcode::kLoadStackPointer:
         return VisitLeaf(node, kMachPtr);
       case IrOpcode::kStateValues:
index 25597eec652c6b258e68822b687cc56eaebcc642..e11730e6e58a695f14608e7b247179d4e4e92bcb 100644 (file)
@@ -1506,6 +1506,11 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
     case Runtime::kInlineIsFunction:
     case Runtime::kInlineIsRegExp:
       return Bounds(Type::None(zone()), Type::Boolean(zone()));
+    case Runtime::kInlineOptimizedDoubleLo:
+    case Runtime::kInlineOptimizedDoubleHi:
+      return Bounds(Type::None(zone()), Type::Signed32());
+    case Runtime::kInlineOptimizedConstructDouble:
+      return Bounds(Type::None(zone()), Type::Number());
     default:
       break;
   }
@@ -2098,6 +2103,26 @@ Bounds Typer::Visitor::TypeFloat64RoundTiesAway(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeFloat64ExtractLowWord32(Node* node) {
+  return Bounds(Type::Signed32());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64ExtractHighWord32(Node* node) {
+  return Bounds(Type::Signed32());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64InsertLowWord32(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat64InsertHighWord32(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
 Bounds Typer::Visitor::TypeLoadStackPointer(Node* node) {
   return Bounds(Type::Internal());
 }
index b502621d506974ac04f5f8bb434ca1322e457260..77e13e7d6a0e82f907a10256f60106cd5cf1f60a 100644 (file)
@@ -805,13 +805,17 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kChangeFloat32ToFloat64:
     case IrOpcode::kChangeFloat64ToInt32:
     case IrOpcode::kChangeFloat64ToUint32:
+    case IrOpcode::kFloat64ExtractLowWord32:
+    case IrOpcode::kFloat64ExtractHighWord32:
+    case IrOpcode::kFloat64InsertLowWord32:
+    case IrOpcode::kFloat64InsertHighWord32:
     case IrOpcode::kLoadStackPointer:
     case IrOpcode::kCheckedLoad:
     case IrOpcode::kCheckedStore:
       // TODO(rossberg): Check.
       break;
   }
-}
+}  // NOLINT(readability/fn_size)
 
 
 void Verifier::Run(Graph* graph, Typing typing) {
index 8bb0d6c936da82e9ed108dba0ab264dfa1b7eab9..b808e4e893072a7a2d654694109c71ee6ccfa9ce 100644 (file)
@@ -18,6 +18,9 @@ namespace compiler {
 #define __ masm()->
 
 
+#define kScratchDoubleReg xmm0
+
+
 // Adds X64 specific methods for decoding operands.
 class X64OperandConverter : public InstructionOperandConverter {
  public:
@@ -28,8 +31,8 @@ class X64OperandConverter : public InstructionOperandConverter {
     return ToImmediate(instr_->InputAt(index));
   }
 
-  Operand InputOperand(size_t index) {
-    return ToOperand(instr_->InputAt(index));
+  Operand InputOperand(size_t index, int extra = 0) {
+    return ToOperand(instr_->InputAt(index), extra);
   }
 
   Operand OutputOperand() { return ToOperand(instr_->Output()); }
@@ -808,6 +811,41 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       }
       __ cvtqsi2sd(i.OutputDoubleRegister(), kScratchRegister);
       break;
+    case kSSEFloat64ExtractLowWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ movl(i.OutputRegister(), i.InputOperand(0));
+      } else {
+        __ movd(i.OutputRegister(), i.InputDoubleRegister(0));
+      }
+      break;
+    case kSSEFloat64ExtractHighWord32:
+      if (instr->InputAt(0)->IsDoubleStackSlot()) {
+        __ movl(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2));
+      } else {
+        __ Pextrd(i.OutputRegister(), i.InputDoubleRegister(0), 1);
+      }
+      break;
+    case kSSEFloat64InsertLowWord32:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0);
+      } else {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
+      }
+      break;
+    case kSSEFloat64InsertHighWord32:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1);
+      } else {
+        __ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
+      }
+      break;
+    case kSSEFloat64LoadLowWord32:
+      if (instr->InputAt(0)->IsRegister()) {
+        __ movd(i.OutputDoubleRegister(), i.InputRegister(0));
+      } else {
+        __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
+      }
+      break;
     case kAVXFloat64Add:
       ASSEMBLE_AVX_DOUBLE_BINOP(vaddsd);
       break;
@@ -1014,7 +1052,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
       break;
   }
-}
+}  // NOLINT(readability/fn_size)
 
 
 // Assembles branches after this instruction.
index 77e3e52158dc9e6cf06a58ed9677dd51ce0b6e70..6af32b01913444711341b9e09cc2e4a888278adf 100644 (file)
@@ -62,6 +62,11 @@ namespace compiler {
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
   V(SSEUint32ToFloat64)            \
+  V(SSEFloat64ExtractLowWord32)    \
+  V(SSEFloat64ExtractHighWord32)   \
+  V(SSEFloat64InsertLowWord32)     \
+  V(SSEFloat64InsertHighWord32)    \
+  V(SSEFloat64LoadLowWord32)       \
   V(AVXFloat64Add)                 \
   V(AVXFloat64Sub)                 \
   V(AVXFloat64Mul)                 \
index 5c63f6330102146f6bb6c7ee0c6356ea719481b5..b00eee16dabb4a04725d1b51ae1108b2894eaa6d 100644 (file)
@@ -1371,6 +1371,43 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractLowWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSEFloat64ExtractHighWord32, g.DefineAsRegister(node),
+       g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Float64Matcher mleft(left);
+  if (mleft.HasValue() && (bit_cast<uint64_t>(mleft.Value()) >> 32) == 0u) {
+    Emit(kSSEFloat64LoadLowWord32, g.DefineAsRegister(node), g.Use(right));
+    return;
+  }
+  Emit(kSSEFloat64InsertLowWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
+void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
+  X64OperandGenerator g(this);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  Emit(kSSEFloat64InsertHighWord32, g.DefineSameAsFirst(node),
+       g.UseRegister(left), g.Use(right));
+}
+
+
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
index 4be27ceeabaaec16394ce63a4965e8ed0f563a42..05d1bdd4f2178c73885a431aa5142ec276469d22 100644 (file)
@@ -2217,6 +2217,24 @@ void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::punpckldq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x62);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x6A);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   EMIT(0xF2);
index ea5a7e25933a0301b2abc8f70ba90663e030415a..41b83481b2dbd4e736aaed98d8454a0c6e9f68e0 100644 (file)
@@ -1018,6 +1018,9 @@ class Assembler : public AssemblerBase {
   void cmpltsd(XMMRegister dst, XMMRegister src);
   void pcmpeqd(XMMRegister dst, XMMRegister src);
 
+  void punpckldq(XMMRegister dst, XMMRegister src);
+  void punpckhdq(XMMRegister dst, XMMRegister src);
+
   void movdqa(XMMRegister dst, const Operand& src);
   void movdqa(const Operand& dst, XMMRegister src);
   void movdqu(XMMRegister dst, const Operand& src);
index 576c7393ccf44e87c8257dec44995a9143c45452..08ffdde5b4e7632e82d5973975c47f8ac40fd25e 100644 (file)
@@ -1554,6 +1554,20 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
                            NameOfXMMRegister(rm),
                            static_cast<int>(imm8));
             data += 2;
+          } else if (*data == 0x62) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
+                           NameOfXMMRegister(rm));
+            data++;
+          } else if (*data == 0x6A) {
+            data++;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
+                           NameOfXMMRegister(rm));
+            data++;
           } else if (*data == 0x76) {
             data++;
             int mod, regop, rm;
index 81c765e7dba5518e39fea4f6b5072aa07b211755..3c0061f3e5d51d5e39fddf4aa9fd3dcfe5dcaeec 100644 (file)
@@ -2441,6 +2441,41 @@ void MacroAssembler::Move(XMMRegister dst, uint64_t src) {
 }
 
 
+void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) {
+  if (imm8 == 0) {
+    movd(dst, src);
+    return;
+  }
+  DCHECK_EQ(1, imm8);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pextrd(dst, src, imm8);
+    return;
+  }
+  pshufd(xmm0, src, 1);
+  movd(dst, src);
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
+  DCHECK(imm8 == 0 || imm8 == 1);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pinsrd(dst, src, imm8);
+    return;
+  }
+  movd(xmm0, src);
+  if (imm8 == 1) {
+    punpckldq(dst, xmm0);
+  } else {
+    DCHECK_EQ(0, imm8);
+    psrlq(dst, 32);
+    punpckldq(xmm0, dst);
+    movaps(dst, xmm0);
+  }
+}
+
+
 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
   if (FLAG_native_code_counters && counter->Enabled()) {
     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
index 2f1354bbf99b87d7af1209e62f4c0954096ba1bc..8c135f2b6021c9b71e5dbf3eea44138fedb7c7a3 100644 (file)
@@ -813,6 +813,13 @@ class MacroAssembler: public Assembler {
   void Push(Register src) { push(src); }
   void Pop(Register dst) { pop(dst); }
 
+  // Non-SSE2 instructions.
+  void Pextrd(Register dst, XMMRegister src, int8_t imm8);
+  void Pinsrd(XMMRegister dst, Register src, int8_t imm8) {
+    Pinsrd(dst, Operand(src), imm8);
+  }
+  void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
+
   // Emit call to the code we are currently generating.
   void CallSelf() {
     Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
index 697a6fa82252421f44f3ff10293337898c228076..5b09bc204246bd335a62bbb8fb0514306f08c0f8 100644 (file)
@@ -2529,6 +2529,16 @@ void Assembler::movd(XMMRegister dst, Register src) {
 }
 
 
+void Assembler::movd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x6E);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::movd(Register dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0x66);
@@ -2632,6 +2642,45 @@ void Assembler::extractps(Register dst, XMMRegister src, byte imm8) {
 }
 
 
+void Assembler::pextrd(Register dst, XMMRegister src, int8_t imm8) {
+  DCHECK(IsEnabled(SSE4_1));
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(src, dst);
+  emit(0x0F);
+  emit(0x3A);
+  emit(0x16);
+  emit_sse_operand(src, dst);
+  emit(imm8);
+}
+
+
+void Assembler::pinsrd(XMMRegister dst, Register src, int8_t imm8) {
+  DCHECK(IsEnabled(SSE4_1));
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x3A);
+  emit(0x22);
+  emit_sse_operand(dst, src);
+  emit(imm8);
+}
+
+
+void Assembler::pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
+  DCHECK(IsEnabled(SSE4_1));
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x3A);
+  emit(0x22);
+  emit_sse_operand(dst, src);
+  emit(imm8);
+}
+
+
 void Assembler::movsd(const Operand& dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0xF2);  // double
@@ -3246,6 +3295,26 @@ void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::punpckldq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x62);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x6A);
+  emit_sse_operand(dst, src);
+}
+
+
 // AVX instructions
 void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
                        XMMRegister src2) {
index 96715d139484735459b04291f66fd001f38c7c6a..9c52b772686316c20e132cf5eede5057d4061bc8 100644 (file)
@@ -1064,6 +1064,7 @@ class Assembler : public AssemblerBase {
 
   // SSE2 instructions
   void movd(XMMRegister dst, Register src);
+  void movd(XMMRegister dst, const Operand& src);
   void movd(Register dst, XMMRegister src);
   void movq(XMMRegister dst, Register src);
   void movq(Register dst, XMMRegister src);
@@ -1132,9 +1133,17 @@ class Assembler : public AssemblerBase {
 
   void movmskpd(Register dst, XMMRegister src);
 
+  void punpckldq(XMMRegister dst, XMMRegister src);
+  void punpckhdq(XMMRegister dst, XMMRegister src);
+
   // SSE 4.1 instruction
   void extractps(Register dst, XMMRegister src, byte imm8);
 
+  void pextrd(Register dst, XMMRegister src, int8_t imm8);
+
+  void pinsrd(XMMRegister dst, Register src, int8_t imm8);
+  void pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
+
   enum RoundingMode {
     kRoundToNearest = 0x0,
     kRoundDown      = 0x1,
index bed99d101a35f8ebccea83a309cded92165e9a80..ba33da779caaef08b780a30712d150d881c9eb3c 100644 (file)
@@ -1179,6 +1179,19 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
         current += PrintRightXMMOperand(current);
         AppendToBuffer(",%d", (*current) & 3);
         current += 1;
+      } else if (third_byte == 0x16) {
+        get_modrm(*current, &mod, &regop, &rm);
+        AppendToBuffer("pextrd ");  // reg/m32, xmm, imm8
+        current += PrintRightOperand(current);
+        AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
+        current += 1;
+      } else if (third_byte == 0x22) {
+        get_modrm(*current, &mod, &regop, &rm);
+        AppendToBuffer("pinsrd ");  // xmm, reg/m32, imm8
+        AppendToBuffer(" %s,", NameOfXMMRegister(regop));
+        current += PrintRightOperand(current);
+        AppendToBuffer(",%d", (*current) & 3);
+        current += 1;
       } else {
         UnimplementedInstruction();
       }
@@ -1229,12 +1242,12 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
         current += PrintRightXMMOperand(current);
       } else if (opcode == 0x72) {
         current += 1;
-        AppendToBuffer("%s,%s,%d", (regop == 6) ? "pslld" : "psrld",
+        AppendToBuffer("%s %s,%d", (regop == 6) ? "pslld" : "psrld",
                        NameOfXMMRegister(rm), *current & 0x7f);
         current += 1;
       } else if (opcode == 0x73) {
         current += 1;
-        AppendToBuffer("%s,%s,%d", (regop == 6) ? "psllq" : "psrlq",
+        AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq",
                        NameOfXMMRegister(rm), *current & 0x7f);
         current += 1;
       } else {
@@ -1251,6 +1264,10 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
           mnemonic = "comisd";
         } else if (opcode == 0x76) {
           mnemonic = "pcmpeqd";
+        } else if (opcode == 0x62) {
+          mnemonic = "punpckldq";
+        } else if (opcode == 0x6A) {
+          mnemonic = "punpckhdq";
         } else {
           UnimplementedInstruction();
         }
index 8e4448d46fceeacfd090b749d86e1e3b98c5a8f1..e4203618fcaa818bdb4441ac3345e3c4d43f0e4f 100644 (file)
@@ -2832,6 +2832,59 @@ void MacroAssembler::Call(Handle<Code> code_object,
 }
 
 
+void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) {
+  if (imm8 == 0) {
+    movd(dst, src);
+    return;
+  }
+  DCHECK_EQ(1, imm8);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pextrd(dst, src, imm8);
+    return;
+  }
+  movq(dst, src);
+  shrq(dst, Immediate(32));
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, Register src, int8_t imm8) {
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pinsrd(dst, src, imm8);
+    return;
+  }
+  movd(xmm0, src);
+  if (imm8 == 1) {
+    punpckldq(dst, xmm0);
+  } else {
+    DCHECK_EQ(0, imm8);
+    psrlq(dst, 32);
+    punpckldq(xmm0, dst);
+    movaps(dst, xmm0);
+  }
+}
+
+
+void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) {
+  DCHECK(imm8 == 0 || imm8 == 1);
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatureScope sse_scope(this, SSE4_1);
+    pinsrd(dst, src, imm8);
+    return;
+  }
+  movd(xmm0, src);
+  if (imm8 == 1) {
+    punpckldq(dst, xmm0);
+  } else {
+    DCHECK_EQ(0, imm8);
+    psrlq(dst, 32);
+    punpckldq(xmm0, dst);
+    movaps(dst, xmm0);
+  }
+}
+
+
 void MacroAssembler::Pushad() {
   Push(rax);
   Push(rcx);
index 47651e2620c0b4147f9a34a2effed90cb51513e8..1eb7f6effefc7c32bbc6ae96ad6f25bb5e80c68a 100644 (file)
@@ -922,6 +922,11 @@ class MacroAssembler: public Assembler {
     Call(self, RelocInfo::CODE_TARGET);
   }
 
+  // Non-SSE2 instructions.
+  void Pextrd(Register dst, XMMRegister src, int8_t imm8);
+  void Pinsrd(XMMRegister dst, Register src, int8_t imm8);
+  void Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8);
+
   // Non-x64 instructions.
   // Push/pop all general purpose registers.
   // Does not push rsp/rbp nor any of the assembler's special purpose registers
index a7b1768d2a541ceac63234314dfee5b087cee5f6..4e30bec9c3c31b081947d199d51ca08ae0f03e0c 100644 (file)
@@ -4647,6 +4647,72 @@ TEST(RunFloat32Constant) {
 }
 
 
+TEST(RunFloat64ExtractLowWord32) {
+  uint64_t input = 0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.Return(m.Float64ExtractLowWord32(m.LoadFromPointer(&input, kMachFloat64)));
+  FOR_FLOAT64_INPUTS(i) {
+    input = bit_cast<uint64_t>(*i);
+    int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(input));
+    CHECK_EQ(expected, m.Call());
+  }
+}
+
+
+TEST(RunFloat64ExtractHighWord32) {
+  uint64_t input = 0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.Return(m.Float64ExtractHighWord32(m.LoadFromPointer(&input, kMachFloat64)));
+  FOR_FLOAT64_INPUTS(i) {
+    input = bit_cast<uint64_t>(*i);
+    int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(input >> 32));
+    CHECK_EQ(expected, m.Call());
+  }
+}
+
+
+TEST(RunFloat64InsertLowWord32) {
+  uint64_t input = 0;
+  uint64_t result = 0;
+  RawMachineAssemblerTester<int32_t> m(kMachInt32);
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64InsertLowWord32(m.LoadFromPointer(&input, kMachFloat64),
+                               m.Parameter(0)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      input = bit_cast<uint64_t>(*i);
+      uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF))) |
+                          (static_cast<uint64_t>(bit_cast<uint32_t>(*j)));
+      CHECK_EQ(0, m.Call(*j));
+      CHECK_EQ(expected, result);
+    }
+  }
+}
+
+
+TEST(RunFloat64InsertHighWord32) {
+  uint64_t input = 0;
+  uint64_t result = 0;
+  RawMachineAssemblerTester<int32_t> m(kMachInt32);
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64InsertHighWord32(m.LoadFromPointer(&input, kMachFloat64),
+                                m.Parameter(0)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      input = bit_cast<uint64_t>(*i);
+      uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF) << 32)) |
+                          (static_cast<uint64_t>(bit_cast<uint32_t>(*j)) << 32);
+      CHECK_EQ(0, m.Call(*j));
+      CHECK_EQ(expected, result);
+    }
+  }
+}
+
+
 static double two_30 = 1 << 30;             // 2^30 is a smi boundary.
 static double two_52 = two_30 * (1 << 22);  // 2^52 is a precision boundary.
 static double kValues[] = {0.1,
index a2eaa15ed341fd6513ca75ec1e0cd7d130222656..215ca76c1d8f5a391328464571845d6dd8bf0809 100644 (file)
@@ -451,6 +451,11 @@ TEST(DisasmIa320) {
     __ psrlq(xmm0, 17);
     __ psrlq(xmm0, xmm1);
     __ por(xmm0, xmm1);
+
+    __ pcmpeqd(xmm1, xmm0);
+
+    __ punpckldq(xmm1, xmm6);
+    __ punpckhdq(xmm7, xmm5);
   }
 
   // cmov.
index 6cd58ec209bb92a3ff8e0e4123ae236e6b894f92..3b78b640ae5d2719759a3e51570eeec812b6911d 100644 (file)
@@ -446,6 +446,9 @@ TEST(DisasmX64) {
     __ psrlq(xmm0, 6);
 
     __ pcmpeqd(xmm1, xmm0);
+
+    __ punpckldq(xmm1, xmm11);
+    __ punpckhdq(xmm8, xmm15);
   }
 
   // cmov.
@@ -472,6 +475,10 @@ TEST(DisasmX64) {
     if (CpuFeatures::IsSupported(SSE4_1)) {
       CpuFeatureScope scope(&assm, SSE4_1);
       __ extractps(rax, xmm1, 0);
+      __ pextrd(rbx, xmm15, 0);
+      __ pextrd(r12, xmm0, 1);
+      __ pinsrd(xmm9, r9, 0);
+      __ pinsrd(xmm5, rax, 1);
     }
   }
 
diff --git a/test/mjsunit/asm/construct-double.js b/test/mjsunit/asm/construct-double.js
new file mode 100644 (file)
index 0000000..8bb5000
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var stdlib = this;
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  function cd1(i, j) {
+    i = i|0;
+    j = j|0;
+    return +%_ConstructDouble(i, j);
+  }
+  function cd2(i) {
+    i = i|0;
+    return +%_ConstructDouble(0, i);
+  }
+  return { cd1: cd1, cd2: cd2 };
+})(stdlib, foreign, heap);
+
+assertEquals(0.0, m.cd1(0, 0));
+assertEquals(%ConstructDouble(0, 1), m.cd2(1));
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(%ConstructDouble(0, i), m.cd2(i));
+  for (var j = -2147483648; j < 2147483648; j += 3999773) {
+    assertEquals(%ConstructDouble(i, j), m.cd1(i, j));
+  }
+}
diff --git a/test/mjsunit/asm/double-hi.js b/test/mjsunit/asm/double-hi.js
new file mode 100644 (file)
index 0000000..5a5f942
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var stdlib = this;
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  function hi1(i) {
+    i = +i;
+    return %_DoubleHi(i)|0;
+  }
+  function hi2(i, j) {
+    i = +i;
+    j = +j;
+    return %_DoubleHi(i)+%_DoubleHi(j)|0;
+  }
+  return { hi1: hi1, hi2: hi2 };
+})(stdlib, foreign, heap);
+
+assertEquals(0, m.hi1(0.0));
+assertEquals(-2147483648, m.hi1(-0.0));
+assertEquals(2146435072, m.hi1(Infinity));
+assertEquals(-1048576, m.hi1(-Infinity));
+assertEquals(0, m.hi2(0.0, 0.0));
+assertEquals(-2147483648, m.hi2(0.0, -0.0));
+assertEquals(-2147483648, m.hi2(-0.0, 0.0));
+assertEquals(0, m.hi2(-0.0, -0.0));
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(%_DoubleHi(i), m.hi1(i));
+  assertEquals(i, m.hi1(%ConstructDouble(i, 0)));
+  assertEquals(i, m.hi1(%ConstructDouble(i, i)));
+  assertEquals(i+i|0, m.hi2(%ConstructDouble(i, 0), %ConstructDouble(i, 0)));
+  assertEquals(i+i|0, m.hi2(%ConstructDouble(i, i), %ConstructDouble(i, i)));
+}
diff --git a/test/mjsunit/asm/double-lo.js b/test/mjsunit/asm/double-lo.js
new file mode 100644 (file)
index 0000000..39d5b52
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var stdlib = this;
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  function lo1(i) {
+    i = +i;
+    return %_DoubleLo(i)|0;
+  }
+  function lo2(i, j) {
+    i = +i;
+    j = +j;
+    return %_DoubleLo(i)+%_DoubleLo(j)|0;
+  }
+  return { lo1: lo1, lo2: lo2 };
+})(stdlib, foreign, heap);
+
+assertEquals(0, m.lo1(0.0));
+assertEquals(0, m.lo1(-0.0));
+assertEquals(0, m.lo1(Infinity));
+assertEquals(0, m.lo1(-Infinity));
+assertEquals(0, m.lo2(0.0, 0.0));
+assertEquals(0, m.lo2(0.0, -0.0));
+assertEquals(0, m.lo2(-0.0, 0.0));
+assertEquals(0, m.lo2(-0.0, -0.0));
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(%_DoubleLo(i), m.lo1(i));
+  assertEquals(i, m.lo1(%ConstructDouble(0, i)));
+  assertEquals(i, m.lo1(%ConstructDouble(i, i)));
+  assertEquals(i+i|0, m.lo2(%ConstructDouble(0, i), %ConstructDouble(0, i)));
+  assertEquals(i+i|0, m.lo2(%ConstructDouble(i, i), %ConstructDouble(i, i)));
+}
index 20d5c069fe295dc8f47c6895674026fb8857dd60..7060a90cf7b2ca7c0c5a74f20ef4633195e77601 100644 (file)
@@ -41,6 +41,61 @@ class JSIntrinsicLoweringTest : public GraphTest {
 };
 
 
+// -----------------------------------------------------------------------------
+// %_ConstructDouble
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) {
+  Node* const input0 = Parameter(0);
+  Node* const input1 = Parameter(1);
+  Node* const context = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(graph()->NewNode(
+      javascript()->CallRuntime(Runtime::kInlineOptimizedConstructDouble, 2),
+      input0, input1, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32(
+                                   IsFloat64InsertLowWord32(
+                                       IsNumberConstant(BitEq(0.0)), input1),
+                                   input0));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_DoubleLo
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(graph()->NewNode(
+      javascript()->CallRuntime(Runtime::kInlineOptimizedDoubleLo, 1), input,
+      context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// %_DoubleHi
+
+
+TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) {
+  Node* const input = Parameter(0);
+  Node* const context = Parameter(1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction const r = Reduce(graph()->NewNode(
+      javascript()->CallRuntime(Runtime::kInlineOptimizedDoubleHi, 1), input,
+      context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input));
+}
+
+
 // -----------------------------------------------------------------------------
 // %_IsSmi
 
index e41b01506117dced5c7bd1db8cbb11c9736ae961..11c679cb296f4a95f62726c738f2f0d35880c584 100644 (file)
@@ -1435,6 +1435,46 @@ TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) {
 }
 
 
+// -----------------------------------------------------------------------------
+// Float64InsertLowWord32
+
+
+TEST_F(MachineOperatorReducerTest, Float64InsertLowWord32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    TRACED_FOREACH(uint32_t, y, kUint32Values) {
+      Reduction const r =
+          Reduce(graph()->NewNode(machine()->Float64InsertLowWord32(),
+                                  Float64Constant(x), Uint32Constant(y)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsFloat64Constant(BitEq(bit_cast<double>(
+              (bit_cast<uint64_t>(x) & V8_UINT64_C(0xFFFFFFFF00000000)) | y))));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Float64InsertHighWord32
+
+
+TEST_F(MachineOperatorReducerTest, Float64InsertHighWord32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    TRACED_FOREACH(uint32_t, y, kUint32Values) {
+      Reduction const r =
+          Reduce(graph()->NewNode(machine()->Float64InsertHighWord32(),
+                                  Float64Constant(x), Uint32Constant(y)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsFloat64Constant(BitEq(bit_cast<double>(
+                      (bit_cast<uint64_t>(x) & V8_UINT64_C(0xFFFFFFFF)) |
+                      (static_cast<uint64_t>(y) << 32)))));
+    }
+  }
+}
+
+
 // -----------------------------------------------------------------------------
 // Store
 
index 6e0df2ab44115f18cf6da30596d5dbef0f47d2aa..dc649e178edb54389befd4b3a12fe8859757f82c 100644 (file)
@@ -206,7 +206,11 @@ const PureOperator kPureOperators[] = {
     PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1),
     PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
     PURE(Float64Floor, 1, 0, 1), PURE(Float64Ceil, 1, 0, 1),
-    PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1)
+    PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1),
+    PURE(Float64ExtractLowWord32, 1, 0, 1),
+    PURE(Float64ExtractHighWord32, 1, 0, 1),
+    PURE(Float64InsertLowWord32, 2, 0, 1),
+    PURE(Float64InsertHighWord32, 2, 0, 1)
 #undef PURE
 };
 
index 72723145851c394836d4ca46fee19f00ec9df624..55771da928c73d1a8c9e8fb99f2854730caa7608 100644 (file)
@@ -1591,6 +1591,8 @@ IS_BINOP_MATCHER(Int32LessThan)
 IS_BINOP_MATCHER(Uint32LessThan)
 IS_BINOP_MATCHER(Uint32LessThanOrEqual)
 IS_BINOP_MATCHER(Float64Sub)
+IS_BINOP_MATCHER(Float64InsertLowWord32)
+IS_BINOP_MATCHER(Float64InsertHighWord32)
 #undef IS_BINOP_MATCHER
 
 
@@ -1614,6 +1616,8 @@ IS_UNOP_MATCHER(Float64Floor)
 IS_UNOP_MATCHER(Float64Ceil)
 IS_UNOP_MATCHER(Float64RoundTruncate)
 IS_UNOP_MATCHER(Float64RoundTiesAway)
+IS_UNOP_MATCHER(Float64ExtractLowWord32)
+IS_UNOP_MATCHER(Float64ExtractHighWord32)
 IS_UNOP_MATCHER(NumberToInt32)
 IS_UNOP_MATCHER(NumberToUint32)
 IS_UNOP_MATCHER(ObjectIsSmi)
index 2f28a94d1dbbe3e597213365637fcb080d091c42..c1d580c56bcfe36c5be973310cc0e929793323ff 100644 (file)
@@ -210,6 +210,12 @@ Matcher<Node*> IsFloat64Floor(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64Ceil(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64RoundTruncate(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsFloat64RoundTiesAway(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64ExtractLowWord32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64ExtractHighWord32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64InsertLowWord32(const Matcher<Node*>& lhs_matcher,
+                                        const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat64InsertHighWord32(const Matcher<Node*>& lhs_matcher,
+                                         const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
                           const Matcher<Node*>& context_matcher,
                           const Matcher<Node*>& effect_matcher,