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());
V(ArmVcvtF64U32) \
V(ArmVcvtS32F64) \
V(ArmVcvtU32F64) \
+ V(ArmVmovLowU32F64) \
+ V(ArmVmovLowF64U32) \
+ V(ArmVmovHighU32F64) \
+ V(ArmVmovHighF64U32) \
+ V(ArmVmovF64U32U32) \
V(ArmVldrF32) \
V(ArmVstrF32) \
V(ArmVldrF64) \
}
+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() {
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;
V(Arm64Float64ToUint32) \
V(Arm64Int32ToFloat64) \
V(Arm64Uint32ToFloat64) \
+ V(Arm64Float64ExtractLowWord32) \
+ V(Arm64Float64ExtractHighWord32) \
+ V(Arm64Float64InsertLowWord32) \
+ V(Arm64Float64InsertHighWord32) \
V(Arm64LdrS) \
V(Arm64StrS) \
V(Arm64LdrD) \
}
+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() {
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) {
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),
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat64) \
V(SSEUint32ToFloat64) \
+ V(SSEFloat64ExtractLowWord32) \
+ V(SSEFloat64ExtractHighWord32) \
+ V(SSEFloat64InsertLowWord32) \
+ V(SSEFloat64InsertHighWord32) \
+ V(SSEFloat64LoadLowWord32) \
V(AVXFloat64Add) \
V(AVXFloat64Sub) \
V(AVXFloat64Mul) \
}
+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() {
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());
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: {
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:
}
+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)) {
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);
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:
}
+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();
}
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_; }
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)
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);
#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);
};
V(Float64Ceil) \
V(Float64RoundTruncate) \
V(Float64RoundTiesAway) \
+ V(Float64ExtractLowWord32) \
+ V(Float64ExtractHighWord32) \
+ V(Float64InsertLowWord32) \
+ V(Float64InsertHighWord32) \
V(LoadStackPointer) \
V(CheckedLoad) \
V(CheckedStore)
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);
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.
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:
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;
}
}
+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());
}
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) {
#define __ masm()->
+#define kScratchDoubleReg xmm0
+
+
// Adds X64 specific methods for decoding operands.
class X64OperandConverter : public InstructionOperandConverter {
public:
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()); }
}
__ 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;
ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
break;
}
-}
+} // NOLINT(readability/fn_size)
// Assembles branches after this instruction.
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat64) \
V(SSEUint32ToFloat64) \
+ V(SSEFloat64ExtractLowWord32) \
+ V(SSEFloat64ExtractHighWord32) \
+ V(SSEFloat64InsertLowWord32) \
+ V(SSEFloat64InsertHighWord32) \
+ V(SSEFloat64LoadLowWord32) \
V(AVXFloat64Add) \
V(AVXFloat64Sub) \
V(AVXFloat64Mul) \
}
+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() {
}
+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);
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);
NameOfXMMRegister(rm),
static_cast<int>(imm8));
data += 2;
+ } else if (*data == 0x62) {
+ data++;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, ®op, &rm);
+ AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
+ NameOfXMMRegister(rm));
+ data++;
+ } else if (*data == 0x6A) {
+ data++;
+ int mod, regop, rm;
+ get_modrm(*data, &mod, ®op, &rm);
+ AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
+ NameOfXMMRegister(rm));
+ data++;
} else if (*data == 0x76) {
data++;
int mod, regop, rm;
}
+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));
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()));
}
+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);
}
+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
}
+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) {
// 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);
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,
current += PrintRightXMMOperand(current);
AppendToBuffer(",%d", (*current) & 3);
current += 1;
+ } else if (third_byte == 0x16) {
+ get_modrm(*current, &mod, ®op, &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, ®op, &rm);
+ AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8
+ AppendToBuffer(" %s,", NameOfXMMRegister(regop));
+ current += PrintRightOperand(current);
+ AppendToBuffer(",%d", (*current) & 3);
+ current += 1;
} else {
UnimplementedInstruction();
}
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 {
mnemonic = "comisd";
} else if (opcode == 0x76) {
mnemonic = "pcmpeqd";
+ } else if (opcode == 0x62) {
+ mnemonic = "punpckldq";
+ } else if (opcode == 0x6A) {
+ mnemonic = "punpckhdq";
} else {
UnimplementedInstruction();
}
}
+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);
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
}
+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,
__ psrlq(xmm0, 17);
__ psrlq(xmm0, xmm1);
__ por(xmm0, xmm1);
+
+ __ pcmpeqd(xmm1, xmm0);
+
+ __ punpckldq(xmm1, xmm6);
+ __ punpckhdq(xmm7, xmm5);
}
// cmov.
__ psrlq(xmm0, 6);
__ pcmpeqd(xmm1, xmm0);
+
+ __ punpckldq(xmm1, xmm11);
+ __ punpckhdq(xmm8, xmm15);
}
// cmov.
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);
}
}
--- /dev/null
+// 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));
+ }
+}
--- /dev/null
+// 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)));
+}
--- /dev/null
+// 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)));
+}
};
+// -----------------------------------------------------------------------------
+// %_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
}
+// -----------------------------------------------------------------------------
+// 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
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
};
IS_BINOP_MATCHER(Uint32LessThan)
IS_BINOP_MATCHER(Uint32LessThanOrEqual)
IS_BINOP_MATCHER(Float64Sub)
+IS_BINOP_MATCHER(Float64InsertLowWord32)
+IS_BINOP_MATCHER(Float64InsertHighWord32)
#undef IS_BINOP_MATCHER
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)
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,