Index: src/ia32/lithium-codegen-ia32.cc |
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc |
index eb1f960c0a738d48595287a90429882c4ea9faaa..cd34868742db673c3763d5610e6618f4e115c7bd 100644 |
--- a/src/ia32/lithium-codegen-ia32.cc |
+++ b/src/ia32/lithium-codegen-ia32.cc |
@@ -541,6 +541,21 @@ XMMRegister LCodeGen::ToDoubleRegister(int index) const { |
} |
+XMMRegister LCodeGen::ToXMMRegister(int index) const { |
+ return XMMRegister::FromAllocationIndex(index); |
+} |
+ |
+ |
+XMMRegister LCodeGen::ToFloat32x4Register(int index) const { |
+ return Float32x4Register::FromAllocationIndex(index); |
+} |
+ |
+ |
+XMMRegister LCodeGen::ToInt32x4Register(int index) const { |
+ return Int32x4Register::FromAllocationIndex(index); |
+} |
+ |
+ |
void LCodeGen::X87LoadForUsage(X87Register reg) { |
ASSERT(x87_stack_.Contains(reg)); |
x87_stack_.Fxch(reg); |
@@ -763,6 +778,24 @@ XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const { |
} |
+XMMRegister LCodeGen::ToFloat32x4Register(LOperand* op) const { |
+ ASSERT(op->IsFloat32x4Register()); |
+ return ToFloat32x4Register(op->index()); |
+} |
+ |
+ |
+XMMRegister LCodeGen::ToInt32x4Register(LOperand* op) const { |
+ ASSERT(op->IsInt32x4Register()); |
+ return ToInt32x4Register(op->index()); |
+} |
+ |
+ |
+XMMRegister LCodeGen::ToXMMRegister(LOperand* op) const { |
+ ASSERT(op->IsFloat32x4Register() || op->IsInt32x4Register()); |
+ return ToXMMRegister(op->index()); |
+} |
+ |
+ |
int32_t LCodeGen::ToInteger32(LConstantOperand* op) const { |
return ToRepresentation(op, Representation::Integer32()); |
} |
@@ -818,7 +851,10 @@ static int ArgumentsOffsetWithoutFrame(int index) { |
Operand LCodeGen::ToOperand(LOperand* op) const { |
if (op->IsRegister()) return Operand(ToRegister(op)); |
if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op)); |
- ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); |
+ if (op->IsFloat32x4Register()) return Operand(ToFloat32x4Register(op)); |
+ if (op->IsInt32x4Register()) return Operand(ToInt32x4Register(op)); |
+ ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot() || |
+ op->IsFloat32x4StackSlot() || op->IsInt32x4StackSlot()); |
if (NeedsEagerFrame()) { |
return Operand(ebp, StackSlotOffset(op->index())); |
} else { |
@@ -945,6 +981,10 @@ void LCodeGen::AddToTranslation(LEnvironment* environment, |
} |
} else if (op->IsDoubleStackSlot()) { |
translation->StoreDoubleStackSlot(op->index()); |
+ } else if (op->IsFloat32x4StackSlot()) { |
+ translation->StoreFloat32x4StackSlot(op->index()); |
+ } else if (op->IsInt32x4StackSlot()) { |
+ translation->StoreInt32x4StackSlot(op->index()); |
} else if (op->IsArgument()) { |
ASSERT(is_tagged); |
int src_index = GetStackSlotCount() + op->index(); |
@@ -961,6 +1001,12 @@ void LCodeGen::AddToTranslation(LEnvironment* environment, |
} else if (op->IsDoubleRegister()) { |
XMMRegister reg = ToDoubleRegister(op); |
translation->StoreDoubleRegister(reg); |
+ } else if (op->IsFloat32x4Register()) { |
+ XMMRegister reg = ToFloat32x4Register(op); |
+ translation->StoreFloat32x4Register(reg); |
+ } else if (op->IsInt32x4Register()) { |
+ XMMRegister reg = ToInt32x4Register(op); |
+ translation->StoreInt32x4Register(reg); |
} else if (op->IsConstantOperand()) { |
HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op)); |
int src_index = DefineDeoptimizationLiteral(constant->handle(isolate())); |
@@ -3439,13 +3485,49 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { |
void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
+ class DeferredFloat32x4ToTagged V8_FINAL : public LDeferredCode { |
+ public: |
+ DeferredFloat32x4ToTagged(LCodeGen* codegen, |
+ LInstruction* instr, |
+ const X87Stack& x87_stack) |
+ : LDeferredCode(codegen, x87_stack), instr_(instr) { } |
+ virtual void Generate() V8_OVERRIDE { |
+ codegen()->DoDeferredFloat32x4ToTagged(instr_); |
+ } |
+ virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
+ private: |
+ LInstruction* instr_; |
+ }; |
+ |
+ class DeferredInt32x4ToTagged V8_FINAL : public LDeferredCode { |
+ public: |
+ DeferredInt32x4ToTagged(LCodeGen* codegen, |
+ LInstruction* instr, |
+ const X87Stack& x87_stack) |
+ : LDeferredCode(codegen, x87_stack), instr_(instr) { } |
+ virtual void Generate() V8_OVERRIDE { |
+ codegen()->DoDeferredInt32x4ToTagged(instr_); |
+ } |
+ virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
+ private: |
+ LInstruction* instr_; |
+ }; |
+ |
ElementsKind elements_kind = instr->elements_kind(); |
LOperand* key = instr->key(); |
- if (!key->IsConstantOperand() && |
- ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), |
- elements_kind)) { |
- __ SmiUntag(ToRegister(key)); |
+ if (!key->IsConstantOperand()) { |
+ if (ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), |
+ elements_kind)) { |
+ if (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS || |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS) { |
+ // Double the index as Float32x4 and Int32x4 need scale 16. |
+ __ shl(ToRegister(key), 1); |
+ } else { |
+ __ SmiUntag(ToRegister(key)); |
+ } |
+ } |
} |
+ |
Operand operand(BuildFastArrayOperand( |
instr->elements(), |
key, |
@@ -3469,6 +3551,47 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
} else { |
X87Mov(ToX87Register(instr->result()), operand); |
} |
+ } else if (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS) { |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ __ movups(ToFloat32x4Register(instr->result()), operand); |
+ } else { |
+ Register reg = ToRegister(instr->result()); |
+ Register tmp = ToRegister(instr->temp()); |
+ DeferredFloat32x4ToTagged* deferred = |
+ new(zone()) DeferredFloat32x4ToTagged(this, instr, x87_stack_); |
+ if (FLAG_inline_new) { |
+ __ AllocateFloat32x4(reg, tmp, deferred->entry()); |
+ } else { |
+ __ jmp(deferred->entry()); |
+ } |
+ __ bind(deferred->exit()); |
+ for (int offset = 0; offset < kFloat32x4Size; offset += kFloatSize) { |
+ __ mov(tmp, Operand(operand, offset)); |
+ __ mov(Operand(FieldOperand(reg, Float32x4::kValueOffset), offset), |
+ tmp); |
+ } |
+ } |
+ } else if (elements_kind == EXTERNAL_INT32x4_ELEMENTS) { |
+ if (CpuFeatures::IsSupported(SSE2)) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ __ movups(ToInt32x4Register(instr->result()), operand); |
+ } else { |
+ Register reg = ToRegister(instr->result()); |
+ Register tmp = ToRegister(instr->temp()); |
+ DeferredInt32x4ToTagged* deferred = |
+ new(zone()) DeferredInt32x4ToTagged(this, instr, x87_stack_); |
+ if (FLAG_inline_new) { |
+ __ AllocateInt32x4(reg, tmp, deferred->entry()); |
+ } else { |
+ __ jmp(deferred->entry()); |
+ } |
+ __ bind(deferred->exit()); |
+ for (int offset = 0; offset < kInt32x4Size; offset += kInt32Size) { |
+ __ mov(tmp, Operand(operand, offset)); |
+ __ mov(Operand(FieldOperand(reg, Int32x4::kValueOffset), offset), tmp); |
+ } |
+ } |
} else { |
Register result(ToRegister(instr->result())); |
switch (elements_kind) { |
@@ -3497,6 +3620,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
break; |
case EXTERNAL_FLOAT_ELEMENTS: |
case EXTERNAL_DOUBLE_ELEMENTS: |
+ case EXTERNAL_FLOAT32x4_ELEMENTS: |
+ case EXTERNAL_INT32x4_ELEMENTS: |
case FAST_SMI_ELEMENTS: |
case FAST_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
@@ -3589,11 +3714,21 @@ Operand LCodeGen::BuildFastArrayOperand( |
Register elements_pointer_reg = ToRegister(elements_pointer); |
int element_shift_size = ElementsKindToShiftSize(elements_kind); |
int shift_size = element_shift_size; |
+ if (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS || |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS) { |
+ // Double the index and use scale 8. Float32x4 needs scale 16. |
+ additional_index *= 2; |
+ } |
if (key->IsConstantOperand()) { |
int constant_value = ToInteger32(LConstantOperand::cast(key)); |
if (constant_value & 0xF0000000) { |
Abort(kArrayIndexConstantValueTooBig); |
} |
+ if (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS || |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS) { |
+ // Double the index and use scale 8. Float32x4 needs scale 16. |
+ constant_value *= 2; |
+ } |
return Operand(elements_pointer_reg, |
((constant_value + additional_index) << shift_size) |
+ offset); |
@@ -3603,6 +3738,8 @@ Operand LCodeGen::BuildFastArrayOperand( |
shift_size -= kSmiTagSize; |
} |
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); |
+ // For Float32x4, make sure the index register is doubled before |
+ // calling this function and restored after its usage. |
return Operand(elements_pointer_reg, |
ToRegister(key), |
scale_factor, |
@@ -4603,11 +4740,19 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
ElementsKind elements_kind = instr->elements_kind(); |
LOperand* key = instr->key(); |
- if (!key->IsConstantOperand() && |
- ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), |
- elements_kind)) { |
- __ SmiUntag(ToRegister(key)); |
+ if (!key->IsConstantOperand()) { |
+ if (ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), |
+ elements_kind)) { |
+ if (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS || |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS) { |
+ // Double the index as Float32x4 and Int32x4 need scale 16. |
+ __ shl(ToRegister(key), 1); |
+ } else { |
+ __ SmiUntag(ToRegister(key)); |
+ } |
+ } |
} |
+ |
Operand operand(BuildFastArrayOperand( |
instr->elements(), |
key, |
@@ -4632,6 +4777,42 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
} else { |
X87Mov(operand, ToX87Register(instr->value())); |
} |
+ } else if (elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS) { |
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ __ movups(operand, ToFloat32x4Register(instr->value())); |
+ } else { |
+ ASSERT(instr->value()->IsRegister()); |
+ Register temp = ToRegister(instr->temp()); |
+ Register input_reg = ToRegister(instr->value()); |
+ __ test(input_reg, Immediate(kSmiTagMask)); |
+ DeoptimizeIf(zero, instr->environment()); |
+ __ CmpObjectType(input_reg, FLOAT32x4_TYPE, temp); |
+ DeoptimizeIf(not_equal, instr->environment()); |
+ for (int offset = 0; offset < kFloat32x4Size; offset += kFloatSize) { |
+ __ mov(temp, |
+ Operand(FieldOperand(input_reg, Float32x4::kValueOffset), offset)); |
+ __ mov(Operand(operand, offset), temp); |
+ } |
+ } |
+ } else if (elements_kind == EXTERNAL_INT32x4_ELEMENTS) { |
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ __ movups(operand, ToInt32x4Register(instr->value())); |
+ } else { |
+ ASSERT(instr->value()->IsRegister()); |
+ Register temp = ToRegister(instr->temp()); |
+ Register input_reg = ToRegister(instr->value()); |
+ __ test(input_reg, Immediate(kSmiTagMask)); |
+ DeoptimizeIf(zero, instr->environment()); |
+ __ CmpObjectType(input_reg, INT32x4_TYPE, temp); |
+ DeoptimizeIf(not_equal, instr->environment()); |
+ for (int offset = 0; offset < kInt32x4Size; offset += kInt32Size) { |
+ __ mov(temp, |
+ Operand(FieldOperand(input_reg, Int32x4::kValueOffset), offset)); |
+ __ mov(Operand(operand, offset), temp); |
+ } |
+ } |
} else { |
Register value = ToRegister(instr->value()); |
switch (elements_kind) { |
@@ -4649,6 +4830,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
__ mov(operand, value); |
break; |
case EXTERNAL_FLOAT_ELEMENTS: |
+ case EXTERNAL_FLOAT32x4_ELEMENTS: |
+ case EXTERNAL_INT32x4_ELEMENTS: |
case EXTERNAL_DOUBLE_ELEMENTS: |
case FAST_SMI_ELEMENTS: |
case FAST_ELEMENTS: |
@@ -6126,6 +6309,16 @@ Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { |
factory()->heap_number_map()); |
final_branch_condition = equal; |
+ } else if (type_name->Equals(heap()->float32x4_string())) { |
+ __ JumpIfSmi(input, false_label, false_distance); |
+ __ CmpObjectType(input, FLOAT32x4_TYPE, input); |
+ final_branch_condition = equal; |
+ |
+ } else if (type_name->Equals(heap()->int32x4_string())) { |
+ __ JumpIfSmi(input, false_label, false_distance); |
+ __ CmpObjectType(input, INT32x4_TYPE, input); |
+ final_branch_condition = equal; |
+ |
} else if (type_name->Equals(heap()->string_string())) { |
__ JumpIfSmi(input, false_label, false_distance); |
__ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); |
@@ -6433,6 +6626,869 @@ void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { |
} |
+void LCodeGen::DoFloat32x4ToTagged(LFloat32x4ToTagged* instr) { |
+ class DeferredFloat32x4ToTagged V8_FINAL : public LDeferredCode { |
+ public: |
+ DeferredFloat32x4ToTagged(LCodeGen* codegen, |
+ LInstruction* instr, |
+ const X87Stack& x87_stack) |
+ : LDeferredCode(codegen, x87_stack), instr_(instr) { } |
+ virtual void Generate() V8_OVERRIDE { |
+ codegen()->DoDeferredFloat32x4ToTagged(instr_); |
+ } |
+ virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
+ private: |
+ LInstruction* instr_; |
+ }; |
+ |
+ CpuFeatureScope scope(masm(), SSE2); |
+ XMMRegister input_reg = ToFloat32x4Register(instr->value()); |
+ Register reg = ToRegister(instr->result()); |
+ Register tmp = ToRegister(instr->temp()); |
+ |
+ DeferredFloat32x4ToTagged* deferred = |
+ new(zone()) DeferredFloat32x4ToTagged(this, instr, x87_stack_); |
+ if (FLAG_inline_new) { |
+ __ AllocateFloat32x4(reg, tmp, deferred->entry()); |
+ } else { |
+ __ jmp(deferred->entry()); |
+ } |
+ __ bind(deferred->exit()); |
+ __ movups(FieldOperand(reg, Float32x4::kValueOffset), input_reg); |
+} |
+ |
+ |
+void LCodeGen::DoDeferredFloat32x4ToTagged(LInstruction* instr) { |
+ // TODO(3095996): Get rid of this. For now, we need to make the |
+ // result register contain a valid pointer because it is already |
+ // contained in the register pointer map. |
+ Register reg = ToRegister(instr->result()); |
+ __ Set(reg, Immediate(0)); |
+ |
+ PushSafepointRegistersScope scope(this); |
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
+ __ CallRuntimeSaveDoubles(Runtime::kAllocateFloat32x4); |
+ RecordSafepointWithRegisters( |
+ instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
+ __ StoreToSafepointRegisterSlot(reg, eax); |
+} |
+ |
+ |
+void LCodeGen::DoTaggedToFloat32x4(LTaggedToFloat32x4* instr) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ Register input_reg = ToRegister(instr->value()); |
+ Register scratch = ToRegister(instr->temp()); |
+ XMMRegister result_reg = ToFloat32x4Register(instr->result()); |
+ |
+ __ test(input_reg, Immediate(kSmiTagMask)); |
+ DeoptimizeIf(zero, instr->environment()); |
+ __ CmpObjectType(input_reg, FLOAT32x4_TYPE, scratch); |
+ DeoptimizeIf(not_equal, instr->environment()); |
+ __ movups(result_reg, FieldOperand(input_reg, Float32x4::kValueOffset)); |
+} |
+ |
+ |
+void LCodeGen::DoInt32x4ToTagged(LInt32x4ToTagged* instr) { |
+ class DeferredInt32x4ToTagged V8_FINAL : public LDeferredCode { |
+ public: |
+ DeferredInt32x4ToTagged(LCodeGen* codegen, |
+ LInstruction* instr, |
+ const X87Stack& x87_stack) |
+ : LDeferredCode(codegen, x87_stack), instr_(instr) { } |
+ virtual void Generate() V8_OVERRIDE { |
+ codegen()->DoDeferredInt32x4ToTagged(instr_); |
+ } |
+ virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
+ private: |
+ LInstruction* instr_; |
+ }; |
+ |
+ CpuFeatureScope scope(masm(), SSE2); |
+ XMMRegister input_reg = ToInt32x4Register(instr->value()); |
+ Register reg = ToRegister(instr->result()); |
+ Register tmp = ToRegister(instr->temp()); |
+ |
+ DeferredInt32x4ToTagged* deferred = |
+ new(zone()) DeferredInt32x4ToTagged(this, instr, x87_stack_); |
+ if (FLAG_inline_new) { |
+ __ AllocateInt32x4(reg, tmp, deferred->entry()); |
+ } else { |
+ __ jmp(deferred->entry()); |
+ } |
+ __ bind(deferred->exit()); |
+ __ movups(FieldOperand(reg, Int32x4::kValueOffset), input_reg); |
+} |
+ |
+ |
+void LCodeGen::DoDeferredInt32x4ToTagged(LInstruction* instr) { |
+ // TODO(3095996): Get rid of this. For now, we need to make the |
+ // result register contain a valid pointer because it is already |
+ // contained in the register pointer map. |
+ Register reg = ToRegister(instr->result()); |
+ __ Set(reg, Immediate(0)); |
+ |
+ PushSafepointRegistersScope scope(this); |
+ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
+ __ CallRuntimeSaveDoubles(Runtime::kAllocateInt32x4); |
+ // Ensure that value in rax survives popping registers. |
+ RecordSafepointWithRegisters( |
+ instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
+ __ StoreToSafepointRegisterSlot(reg, eax); |
+} |
+ |
+ |
+void LCodeGen::DoTaggedToInt32x4(LTaggedToInt32x4* instr) { |
+ LOperand* input = instr->value(); |
+ ASSERT(input->IsRegister()); |
+ LOperand* result = instr->result(); |
+ ASSERT(result->IsInt32x4Register()); |
+ |
+ Register input_reg = ToRegister(input); |
+ Register scratch = ToRegister(instr->temp()); |
+ XMMRegister result_reg = ToInt32x4Register(result); |
+ |
+ CpuFeatureScope scope(masm(), SSE2); |
+ __ test(input_reg, Immediate(kSmiTagMask)); |
+ DeoptimizeIf(zero, instr->environment()); |
+ __ CmpObjectType(input_reg, INT32x4_TYPE, scratch); |
+ DeoptimizeIf(not_equal, instr->environment()); |
+ __ movups(result_reg, FieldOperand(input_reg, Int32x4::kValueOffset)); |
+} |
+ |
+ |
+void LCodeGen::DoNullarySIMDOperation(LNullarySIMDOperation* instr) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ switch (instr->op()) { |
+ case kFloat32x4Zero: { |
+ XMMRegister result_reg = ToFloat32x4Register(instr->result()); |
+ __ xorps(result_reg, result_reg); |
+ return; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return; |
+ } |
+} |
+ |
+ |
+void LCodeGen::DoUnarySIMDOperation(LUnarySIMDOperation* instr) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ uint8_t select = 0; |
+ switch (instr->op()) { |
+ case kFloat32x4OrInt32x4Change: { |
+ Comment(";;; deoptimize: can not perform representation change" |
+ "for float32x4 or int32x4"); |
+ DeoptimizeIf(no_condition, instr->environment()); |
+ return; |
+ } |
+ case kSIMDAbs: |
+ case kSIMDNeg: |
+ case kSIMDReciprocal: |
+ case kSIMDReciprocalSqrt: |
+ case kSIMDSqrt: { |
+ ASSERT(instr->value()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->value()->representation().IsFloat32x4()); |
+ XMMRegister input_reg = ToFloat32x4Register(instr->value()); |
+ switch (instr->op()) { |
+ case kSIMDAbs: |
+ __ absps(input_reg); |
+ break; |
+ case kSIMDNeg: |
+ __ negateps(input_reg); |
+ break; |
+ case kSIMDReciprocal: |
+ __ rcpps(input_reg, input_reg); |
+ break; |
+ case kSIMDReciprocalSqrt: |
+ __ rsqrtps(input_reg, input_reg); |
+ break; |
+ case kSIMDSqrt: |
+ __ sqrtps(input_reg, input_reg); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ return; |
+ } |
+ case kSIMDNot: |
+ case kSIMDNegU32: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4()); |
+ XMMRegister input_reg = ToInt32x4Register(instr->value()); |
+ switch (instr->op()) { |
+ case kSIMDNot: |
+ __ notps(input_reg); |
+ break; |
+ case kSIMDNegU32: |
+ __ pnegd(input_reg); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ return; |
+ } |
+ case kSIMDBitsToFloat32x4: |
+ case kSIMDToFloat32x4: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4()); |
+ XMMRegister input_reg = ToInt32x4Register(instr->value()); |
+ XMMRegister result_reg = ToFloat32x4Register(instr->result()); |
+ if (instr->op() == kSIMDBitsToFloat32x4) { |
+ if (!result_reg.is(input_reg)) { |
+ __ movaps(result_reg, input_reg); |
+ } |
+ } else { |
+ ASSERT(instr->op() == kSIMDToFloat32x4); |
+ __ cvtdq2ps(result_reg, input_reg); |
+ } |
+ return; |
+ } |
+ case kSIMDBitsToInt32x4: |
+ case kSIMDToInt32x4: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsFloat32x4()); |
+ XMMRegister input_reg = ToFloat32x4Register(instr->value()); |
+ XMMRegister result_reg = ToInt32x4Register(instr->result()); |
+ if (instr->op() == kSIMDBitsToInt32x4) { |
+ if (!result_reg.is(input_reg)) { |
+ __ movaps(result_reg, input_reg); |
+ } |
+ } else { |
+ ASSERT(instr->op() == kSIMDToInt32x4); |
+ __ cvtps2dq(result_reg, input_reg); |
+ } |
+ return; |
+ } |
+ case kFloat32x4Splat: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsDouble()); |
+ XMMRegister input_reg = ToDoubleRegister(instr->value()); |
+ XMMRegister result_reg = ToFloat32x4Register(instr->result()); |
+ XMMRegister xmm_scratch = xmm0; |
+ __ xorps(xmm_scratch, xmm_scratch); |
+ __ cvtsd2ss(xmm_scratch, input_reg); |
+ __ shufps(xmm_scratch, xmm_scratch, 0x0); |
+ __ movaps(result_reg, xmm_scratch); |
+ return; |
+ } |
+ case kInt32x4Splat: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); |
+ Register input_reg = ToRegister(instr->value()); |
+ XMMRegister result_reg = ToInt32x4Register(instr->result()); |
+ __ movd(result_reg, input_reg); |
+ __ shufps(result_reg, result_reg, 0x0); |
+ return; |
+ } |
+ case kInt32x4SignMask: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4()); |
+ XMMRegister input_reg = ToInt32x4Register(instr->value()); |
+ Register result = ToRegister(instr->result()); |
+ __ movmskps(result, input_reg); |
+ return; |
+ } |
+ case kFloat32x4SignMask: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsFloat32x4()); |
+ XMMRegister input_reg = ToFloat32x4Register(instr->value()); |
+ Register result = ToRegister(instr->result()); |
+ __ movmskps(result, input_reg); |
+ return; |
+ } |
+ case kFloat32x4W: |
+ select++; |
+ case kFloat32x4Z: |
+ select++; |
+ case kFloat32x4Y: |
+ select++; |
+ case kFloat32x4X: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsFloat32x4()); |
+ XMMRegister input_reg = ToFloat32x4Register(instr->value()); |
+ XMMRegister result = ToDoubleRegister(instr->result()); |
+ XMMRegister xmm_scratch = result.is(input_reg) ? xmm0 : result; |
+ |
+ if (select == 0x0) { |
+ __ xorps(xmm_scratch, xmm_scratch); |
+ __ cvtss2sd(xmm_scratch, input_reg); |
+ if (!xmm_scratch.is(result)) { |
+ __ movaps(result, xmm_scratch); |
+ } |
+ } else { |
+ __ pshufd(xmm_scratch, input_reg, select); |
+ if (!xmm_scratch.is(result)) { |
+ __ xorps(result, result); |
+ } |
+ __ cvtss2sd(result, xmm_scratch); |
+ } |
+ return; |
+ } |
+ case kInt32x4X: |
+ case kInt32x4Y: |
+ case kInt32x4Z: |
+ case kInt32x4W: |
+ case kInt32x4FlagX: |
+ case kInt32x4FlagY: |
+ case kInt32x4FlagZ: |
+ case kInt32x4FlagW: { |
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4()); |
+ bool flag = false; |
+ switch (instr->op()) { |
+ case kInt32x4FlagX: |
+ flag = true; |
+ case kInt32x4X: |
+ break; |
+ case kInt32x4FlagY: |
+ flag = true; |
+ case kInt32x4Y: |
+ select = 0x1; |
+ break; |
+ case kInt32x4FlagZ: |
+ flag = true; |
+ case kInt32x4Z: |
+ select = 0x2; |
+ break; |
+ case kInt32x4FlagW: |
+ flag = true; |
+ case kInt32x4W: |
+ select = 0x3; |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ |
+ XMMRegister input_reg = ToInt32x4Register(instr->value()); |
+ Register result = ToRegister(instr->result()); |
+ if (select == 0x0) { |
+ __ movd(result, input_reg); |
+ } else { |
+ if (CpuFeatures::IsSupported(SSE4_1)) { |
+ CpuFeatureScope scope(masm(), SSE4_1); |
+ __ extractps(result, input_reg, select); |
+ } else { |
+ XMMRegister xmm_scratch = xmm0; |
+ __ pshufd(xmm_scratch, input_reg, select); |
+ __ movd(result, xmm_scratch); |
+ } |
+ } |
+ |
+ if (flag) { |
+ Label false_value, done; |
+ __ test(result, result); |
+ __ j(zero, &false_value, Label::kNear); |
+ __ LoadRoot(result, Heap::kTrueValueRootIndex); |
+ __ jmp(&done, Label::kNear); |
+ __ bind(&false_value); |
+ __ LoadRoot(result, Heap::kFalseValueRootIndex); |
+ __ bind(&done); |
+ } |
+ return; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return; |
+ } |
+} |
+ |
+ |
+void LCodeGen::DoBinarySIMDOperation(LBinarySIMDOperation* instr) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ uint8_t imm8 = 0; // for with operation |
+ switch (instr->op()) { |
+ case kSIMDAdd: |
+ case kSIMDSub: |
+ case kSIMDMul: |
+ case kSIMDDiv: |
+ case kSIMDMin: |
+ case kSIMDMax: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->right()->representation().IsFloat32x4()); |
+ XMMRegister left_reg = ToFloat32x4Register(instr->left()); |
+ XMMRegister right_reg = ToFloat32x4Register(instr->right()); |
+ switch (instr->op()) { |
+ case kSIMDAdd: |
+ __ addps(left_reg, right_reg); |
+ break; |
+ case kSIMDSub: |
+ __ subps(left_reg, right_reg); |
+ break; |
+ case kSIMDMul: |
+ __ mulps(left_reg, right_reg); |
+ break; |
+ case kSIMDDiv: |
+ __ divps(left_reg, right_reg); |
+ break; |
+ case kSIMDMin: |
+ __ minps(left_reg, right_reg); |
+ break; |
+ case kSIMDMax: |
+ __ maxps(left_reg, right_reg); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ return; |
+ } |
+ case kSIMDScale: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->right()->representation().IsDouble()); |
+ XMMRegister left_reg = ToFloat32x4Register(instr->left()); |
+ XMMRegister right_reg = ToDoubleRegister(instr->right()); |
+ XMMRegister scratch_reg = xmm0; |
+ __ xorps(scratch_reg, scratch_reg); |
+ __ cvtsd2ss(scratch_reg, right_reg); |
+ __ shufps(scratch_reg, scratch_reg, 0x0); |
+ __ mulps(left_reg, scratch_reg); |
+ return; |
+ } |
+ case kSIMDShuffle: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsFloat32x4()); |
+ if (instr->hydrogen()->right()->IsConstant() && |
+ HConstant::cast(instr->hydrogen()->right())->HasInteger32Value()) { |
+ int32_t value = ToInteger32(LConstantOperand::cast(instr->right())); |
+ uint8_t select = static_cast<uint8_t>(value & 0xFF); |
+ XMMRegister left_reg = ToFloat32x4Register(instr->left()); |
+ __ shufps(left_reg, left_reg, select); |
+ return; |
+ } else { |
+ Comment(";;; deoptimize: non-constant selector for shuffle"); |
+ DeoptimizeIf(no_condition, instr->environment()); |
+ return; |
+ } |
+ } |
+ case kSIMDShuffleU32: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsInt32x4()); |
+ if (instr->hydrogen()->right()->IsConstant() && |
+ HConstant::cast(instr->hydrogen()->right())->HasInteger32Value()) { |
+ int32_t value = ToInteger32(LConstantOperand::cast(instr->right())); |
+ uint8_t select = static_cast<uint8_t>(value & 0xFF); |
+ XMMRegister left_reg = ToInt32x4Register(instr->left()); |
+ __ pshufd(left_reg, left_reg, select); |
+ return; |
+ } else { |
+ Comment(";;; deoptimize: non-constant selector for shuffle"); |
+ DeoptimizeIf(no_condition, instr->environment()); |
+ return; |
+ } |
+ } |
+ case kSIMDLessThan: |
+ case kSIMDLessThanOrEqual: |
+ case kSIMDEqual: |
+ case kSIMDNotEqual: |
+ case kSIMDGreaterThanOrEqual: |
+ case kSIMDGreaterThan: { |
+ ASSERT(instr->hydrogen()->left()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->right()->representation().IsFloat32x4()); |
+ XMMRegister left_reg = ToFloat32x4Register(instr->left()); |
+ XMMRegister right_reg = ToFloat32x4Register(instr->right()); |
+ XMMRegister result_reg = ToInt32x4Register(instr->result()); |
+ switch (instr->op()) { |
+ case kSIMDLessThan: |
+ if (result_reg.is(left_reg)) { |
+ __ cmpltps(result_reg, right_reg); |
+ } else if (result_reg.is(right_reg)) { |
+ __ cmpnltps(result_reg, left_reg); |
+ } else { |
+ __ movaps(result_reg, left_reg); |
+ __ cmpltps(result_reg, right_reg); |
+ } |
+ break; |
+ case kSIMDLessThanOrEqual: |
+ if (result_reg.is(left_reg)) { |
+ __ cmpleps(result_reg, right_reg); |
+ } else if (result_reg.is(right_reg)) { |
+ __ cmpnleps(result_reg, left_reg); |
+ } else { |
+ __ movaps(result_reg, left_reg); |
+ __ cmpleps(result_reg, right_reg); |
+ } |
+ break; |
+ case kSIMDEqual: |
+ if (result_reg.is(left_reg)) { |
+ __ cmpeqps(result_reg, right_reg); |
+ } else if (result_reg.is(right_reg)) { |
+ __ cmpeqps(result_reg, left_reg); |
+ } else { |
+ __ movaps(result_reg, left_reg); |
+ __ cmpeqps(result_reg, right_reg); |
+ } |
+ break; |
+ case kSIMDNotEqual: |
+ if (result_reg.is(left_reg)) { |
+ __ cmpneqps(result_reg, right_reg); |
+ } else if (result_reg.is(right_reg)) { |
+ __ cmpneqps(result_reg, left_reg); |
+ } else { |
+ __ movaps(result_reg, left_reg); |
+ __ cmpneqps(result_reg, right_reg); |
+ } |
+ break; |
+ case kSIMDGreaterThanOrEqual: |
+ if (result_reg.is(left_reg)) { |
+ __ cmpnltps(result_reg, right_reg); |
+ } else if (result_reg.is(right_reg)) { |
+ __ cmpltps(result_reg, left_reg); |
+ } else { |
+ __ movaps(result_reg, left_reg); |
+ __ cmpnltps(result_reg, right_reg); |
+ } |
+ break; |
+ case kSIMDGreaterThan: |
+ if (result_reg.is(left_reg)) { |
+ __ cmpnleps(result_reg, right_reg); |
+ } else if (result_reg.is(right_reg)) { |
+ __ cmpleps(result_reg, left_reg); |
+ } else { |
+ __ movaps(result_reg, left_reg); |
+ __ cmpnleps(result_reg, right_reg); |
+ } |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ return; |
+ } |
+ case kSIMDAnd: |
+ case kSIMDOr: |
+ case kSIMDXor: |
+ case kSIMDAddU32: |
+ case kSIMDSubU32: |
+ case kSIMDMulU32: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsInt32x4()); |
+ ASSERT(instr->hydrogen()->right()->representation().IsInt32x4()); |
+ XMMRegister left_reg = ToInt32x4Register(instr->left()); |
+ XMMRegister right_reg = ToInt32x4Register(instr->right()); |
+ switch (instr->op()) { |
+ case kSIMDAnd: |
+ __ andps(left_reg, right_reg); |
+ break; |
+ case kSIMDOr: |
+ __ orps(left_reg, right_reg); |
+ break; |
+ case kSIMDXor: |
+ __ xorps(left_reg, right_reg); |
+ break; |
+ case kSIMDAddU32: |
+ __ paddd(left_reg, right_reg); |
+ break; |
+ case kSIMDSubU32: |
+ __ psubd(left_reg, right_reg); |
+ break; |
+ case kSIMDMulU32: |
+ if (CpuFeatures::IsSupported(SSE4_1)) { |
+ CpuFeatureScope scope(masm(), SSE4_1); |
+ __ pmulld(left_reg, right_reg); |
+ } else { |
+ // The algorithm is from http://stackoverflow.com/questions/10500766/sse-multiplication-of-4-32-bit-integers |
+ XMMRegister xmm_scratch = xmm0; |
+ __ movaps(xmm_scratch, left_reg); |
+ __ pmuludq(left_reg, right_reg); |
+ __ psrlq(xmm_scratch, 4); |
+ __ psrlq(right_reg, 4); |
+ __ pmuludq(xmm_scratch, right_reg); |
+ __ pshufd(left_reg, left_reg, 8); |
+ __ pshufd(xmm_scratch, xmm_scratch, 8); |
+ __ punpackldq(left_reg, xmm_scratch); |
+ } |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ return; |
+ } |
+ case kSIMDWithW: |
+ imm8++; |
+ case kSIMDWithZ: |
+ imm8++; |
+ case kSIMDWithY: |
+ imm8++; |
+ case kSIMDWithX: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->right()->representation().IsDouble()); |
+ XMMRegister left_reg = ToFloat32x4Register(instr->left()); |
+ XMMRegister right_reg = ToDoubleRegister(instr->right()); |
+ XMMRegister xmm_scratch = xmm0; |
+ __ xorps(xmm_scratch, xmm_scratch); |
+ __ cvtsd2ss(xmm_scratch, right_reg); |
+ if (CpuFeatures::IsSupported(SSE4_1)) { |
+ imm8 = imm8 << 4; |
+ CpuFeatureScope scope(masm(), SSE4_1); |
+ __ insertps(left_reg, xmm_scratch, imm8); |
+ } else { |
+ __ sub(esp, Immediate(kFloat32x4Size)); |
+ __ movups(Operand(esp, 0), left_reg); |
+ __ movss(Operand(esp, imm8 * kFloatSize), xmm_scratch); |
+ __ movups(left_reg, Operand(esp, 0)); |
+ __ add(esp, Immediate(kFloat32x4Size)); |
+ } |
+ return; |
+ } |
+ case kSIMDWithWu32: |
+ imm8++; |
+ case kSIMDWithZu32: |
+ imm8++; |
+ case kSIMDWithYu32: |
+ imm8++; |
+ case kSIMDWithXu32: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsInt32x4()); |
+ ASSERT(instr->hydrogen()->right()->representation().IsInteger32()); |
+ XMMRegister left_reg = ToInt32x4Register(instr->left()); |
+ Register right_reg = ToRegister(instr->right()); |
+ if (CpuFeatures::IsSupported(SSE4_1)) { |
+ CpuFeatureScope scope(masm(), SSE4_1); |
+ __ pinsrd(left_reg, right_reg, imm8); |
+ } else { |
+ __ sub(esp, Immediate(kInt32x4Size)); |
+ __ movdqu(Operand(esp, 0), left_reg); |
+ __ mov(Operand(esp, imm8 * kFloatSize), right_reg); |
+ __ movdqu(left_reg, Operand(esp, 0)); |
+ __ add(esp, Immediate(kInt32x4Size)); |
+ } |
+ return; |
+ } |
+ case kSIMDWithFlagW: |
+ imm8++; |
+ case kSIMDWithFlagZ: |
+ imm8++; |
+ case kSIMDWithFlagY: |
+ imm8++; |
+ case kSIMDWithFlagX: { |
+ ASSERT(instr->left()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->left()->representation().IsInt32x4()); |
+ ASSERT(instr->hydrogen()->right()->representation().IsTagged()); |
+ HType type = instr->hydrogen()->right()->type(); |
+ XMMRegister left_reg = ToInt32x4Register(instr->left()); |
+ Register right_reg = ToRegister(instr->right()); |
+ Label load_false_value, done; |
+ if (type.IsBoolean()) { |
+ __ sub(esp, Immediate(kInt32x4Size)); |
+ __ movups(Operand(esp, 0), left_reg); |
+ __ CompareRoot(right_reg, Heap::kTrueValueRootIndex); |
+ __ j(not_equal, &load_false_value, Label::kNear); |
+ } else { |
+ Comment(";;; deoptimize: other types for SIMD.withFlagX/Y/Z/W."); |
+ DeoptimizeIf(no_condition, instr->environment()); |
+ return; |
+ } |
+ // load true value. |
+ __ mov(Operand(esp, imm8 * kFloatSize), Immediate(0xFFFFFFFF)); |
+ __ jmp(&done, Label::kNear); |
+ __ bind(&load_false_value); |
+ __ mov(Operand(esp, imm8 * kFloatSize), Immediate(0x0)); |
+ __ bind(&done); |
+ __ movups(left_reg, Operand(esp, 0)); |
+ __ add(esp, Immediate(kInt32x4Size)); |
+ return; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return; |
+ } |
+} |
+ |
+ |
+void LCodeGen::DoTernarySIMDOperation(LTernarySIMDOperation* instr) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ switch (instr->op()) { |
+ case kSIMDSelect: { |
+ ASSERT(instr->hydrogen()->first()->representation().IsInt32x4()); |
+ ASSERT(instr->hydrogen()->second()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->third()->representation().IsFloat32x4()); |
+ |
+ XMMRegister mask_reg = ToInt32x4Register(instr->first()); |
+ XMMRegister left_reg = ToFloat32x4Register(instr->second()); |
+ XMMRegister right_reg = ToFloat32x4Register(instr->third()); |
+ XMMRegister result_reg = ToFloat32x4Register(instr->result()); |
+ XMMRegister temp_reg = xmm0; |
+ |
+ // Copy mask. |
+ __ movaps(temp_reg, mask_reg); |
+ // Invert it. |
+ __ notps(temp_reg); |
+ // temp_reg = temp_reg & falseValue. |
+ __ andps(temp_reg, right_reg); |
+ |
+ if (!result_reg.is(mask_reg)) { |
+ if (result_reg.is(left_reg)) { |
+ // result_reg = result_reg & trueValue. |
+ __ andps(result_reg, mask_reg); |
+ // out = result_reg | temp_reg. |
+ __ orps(result_reg, temp_reg); |
+ } else { |
+ __ movaps(result_reg, mask_reg); |
+ // result_reg = result_reg & trueValue. |
+ __ andps(result_reg, left_reg); |
+ // out = result_reg | temp_reg. |
+ __ orps(result_reg, temp_reg); |
+ } |
+ } else { |
+ // result_reg = result_reg & trueValue. |
+ __ andps(result_reg, left_reg); |
+ // out = result_reg | temp_reg. |
+ __ orps(result_reg, temp_reg); |
+ } |
+ return; |
+ } |
+ case kSIMDShuffleMix: { |
+ ASSERT(instr->first()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->first()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->second()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->third()->representation().IsInteger32()); |
+ if (instr->hydrogen()->third()->IsConstant() && |
+ HConstant::cast(instr->hydrogen()->third())->HasInteger32Value()) { |
+ int32_t value = ToInteger32(LConstantOperand::cast(instr->third())); |
+ uint8_t select = static_cast<uint8_t>(value & 0xFF); |
+ XMMRegister first_reg = ToFloat32x4Register(instr->first()); |
+ XMMRegister second_reg = ToFloat32x4Register(instr->second()); |
+ __ shufps(first_reg, second_reg, select); |
+ return; |
+ } else { |
+ Comment(";;; deoptimize: non-constant selector for shuffle"); |
+ DeoptimizeIf(no_condition, instr->environment()); |
+ return; |
+ } |
+ } |
+ case kSIMDClamp: { |
+ ASSERT(instr->first()->Equals(instr->result())); |
+ ASSERT(instr->hydrogen()->first()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->second()->representation().IsFloat32x4()); |
+ ASSERT(instr->hydrogen()->third()->representation().IsFloat32x4()); |
+ |
+ XMMRegister value_reg = ToFloat32x4Register(instr->first()); |
+ XMMRegister lower_reg = ToFloat32x4Register(instr->second()); |
+ XMMRegister upper_reg = ToFloat32x4Register(instr->third()); |
+ __ minps(value_reg, upper_reg); |
+ __ maxps(value_reg, lower_reg); |
+ return; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return; |
+ } |
+} |
+ |
+ |
+void LCodeGen::DoQuarternarySIMDOperation(LQuarternarySIMDOperation* instr) { |
+ CpuFeatureScope scope(masm(), SSE2); |
+ switch (instr->op()) { |
+ case kFloat32x4Constructor: { |
+ ASSERT(instr->hydrogen()->x()->representation().IsDouble()); |
+ ASSERT(instr->hydrogen()->y()->representation().IsDouble()); |
+ ASSERT(instr->hydrogen()->z()->representation().IsDouble()); |
+ ASSERT(instr->hydrogen()->w()->representation().IsDouble()); |
+ XMMRegister x_reg = ToDoubleRegister(instr->x()); |
+ XMMRegister y_reg = ToDoubleRegister(instr->y()); |
+ XMMRegister z_reg = ToDoubleRegister(instr->z()); |
+ XMMRegister w_reg = ToDoubleRegister(instr->w()); |
+ XMMRegister result_reg = ToFloat32x4Register(instr->result()); |
+ __ sub(esp, Immediate(kFloat32x4Size)); |
+ __ xorps(xmm0, xmm0); |
+ __ cvtsd2ss(xmm0, x_reg); |
+ __ movss(Operand(esp, 0 * kFloatSize), xmm0); |
+ __ xorps(xmm0, xmm0); |
+ __ cvtsd2ss(xmm0, y_reg); |
+ __ movss(Operand(esp, 1 * kFloatSize), xmm0); |
+ __ xorps(xmm0, xmm0); |
+ __ cvtsd2ss(xmm0, z_reg); |
+ __ movss(Operand(esp, 2 * kFloatSize), xmm0); |
+ __ xorps(xmm0, xmm0); |
+ __ cvtsd2ss(xmm0, w_reg); |
+ __ movss(Operand(esp, 3 * kFloatSize), xmm0); |
+ __ movups(result_reg, Operand(esp, 0 * kFloatSize)); |
+ __ add(esp, Immediate(kFloat32x4Size)); |
+ return; |
+ } |
+ case kInt32x4Constructor: { |
+ ASSERT(instr->hydrogen()->x()->representation().IsInteger32()); |
+ ASSERT(instr->hydrogen()->y()->representation().IsInteger32()); |
+ ASSERT(instr->hydrogen()->z()->representation().IsInteger32()); |
+ ASSERT(instr->hydrogen()->w()->representation().IsInteger32()); |
+ Register x_reg = ToRegister(instr->x()); |
+ Register y_reg = ToRegister(instr->y()); |
+ Register z_reg = ToRegister(instr->z()); |
+ Register w_reg = ToRegister(instr->w()); |
+ XMMRegister result_reg = ToInt32x4Register(instr->result()); |
+ __ sub(esp, Immediate(kInt32x4Size)); |
+ __ mov(Operand(esp, 0 * kInt32Size), x_reg); |
+ __ mov(Operand(esp, 1 * kInt32Size), y_reg); |
+ __ mov(Operand(esp, 2 * kInt32Size), z_reg); |
+ __ mov(Operand(esp, 3 * kInt32Size), w_reg); |
+ __ movups(result_reg, Operand(esp, 0 * kInt32Size)); |
+ __ add(esp, Immediate(kInt32x4Size)); |
+ return; |
+ } |
+ case kInt32x4Bool: { |
+ ASSERT(instr->hydrogen()->x()->representation().IsTagged()); |
+ ASSERT(instr->hydrogen()->y()->representation().IsTagged()); |
+ ASSERT(instr->hydrogen()->z()->representation().IsTagged()); |
+ ASSERT(instr->hydrogen()->w()->representation().IsTagged()); |
+ HType x_type = instr->hydrogen()->x()->type(); |
+ HType y_type = instr->hydrogen()->y()->type(); |
+ HType z_type = instr->hydrogen()->z()->type(); |
+ HType w_type = instr->hydrogen()->w()->type(); |
+ if (!x_type.IsBoolean() || !y_type.IsBoolean() || |
+ !z_type.IsBoolean() || !w_type.IsBoolean()) { |
+ Comment(";;; deoptimize: other types for int32x4.bool."); |
+ DeoptimizeIf(no_condition, instr->environment()); |
+ return; |
+ } |
+ XMMRegister result_reg = ToInt32x4Register(instr->result()); |
+ Register x_reg = ToRegister(instr->x()); |
+ Register y_reg = ToRegister(instr->y()); |
+ Register z_reg = ToRegister(instr->z()); |
+ Register w_reg = ToRegister(instr->w()); |
+ Label load_false_x, done_x, load_false_y, done_y, |
+ load_false_z, done_z, load_false_w, done_w; |
+ __ sub(esp, Immediate(kInt32x4Size)); |
+ |
+ __ CompareRoot(x_reg, Heap::kTrueValueRootIndex); |
+ __ j(not_equal, &load_false_x, Label::kNear); |
+ __ mov(Operand(esp, 0 * kInt32Size), Immediate(-1)); |
+ __ jmp(&done_x, Label::kNear); |
+ __ bind(&load_false_x); |
+ __ mov(Operand(esp, 0 * kInt32Size), Immediate(0x0)); |
+ __ bind(&done_x); |
+ |
+ __ CompareRoot(y_reg, Heap::kTrueValueRootIndex); |
+ __ j(not_equal, &load_false_y, Label::kNear); |
+ __ mov(Operand(esp, 1 * kInt32Size), Immediate(-1)); |
+ __ jmp(&done_y, Label::kNear); |
+ __ bind(&load_false_y); |
+ __ mov(Operand(esp, 1 * kInt32Size), Immediate(0x0)); |
+ __ bind(&done_y); |
+ |
+ __ CompareRoot(z_reg, Heap::kTrueValueRootIndex); |
+ __ j(not_equal, &load_false_z, Label::kNear); |
+ __ mov(Operand(esp, 2 * kInt32Size), Immediate(-1)); |
+ __ jmp(&done_z, Label::kNear); |
+ __ bind(&load_false_z); |
+ __ mov(Operand(esp, 2 * kInt32Size), Immediate(0x0)); |
+ __ bind(&done_z); |
+ |
+ __ CompareRoot(w_reg, Heap::kTrueValueRootIndex); |
+ __ j(not_equal, &load_false_w, Label::kNear); |
+ __ mov(Operand(esp, 3 * kInt32Size), Immediate(-1)); |
+ __ jmp(&done_w, Label::kNear); |
+ __ bind(&load_false_w); |
+ __ mov(Operand(esp, 3 * kInt32Size), Immediate(0x0)); |
+ __ bind(&done_w); |
+ |
+ __ movups(result_reg, Operand(esp, 0)); |
+ __ add(esp, Immediate(kInt32x4Size)); |
+ return; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return; |
+ } |
+} |
+ |
+ |
#undef __ |
} } // namespace v8::internal |