Index: src/ia32/lithium-ia32.cc |
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc |
index 921b5aa933625703838bcfc9caf8cd52065cb2d4..d0d5744d19b28412e81dd00ed7c9cfe51989be64 100644 |
--- a/src/ia32/lithium-ia32.cc |
+++ b/src/ia32/lithium-ia32.cc |
@@ -387,23 +387,39 @@ void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { |
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) { |
- // Skip a slot if for a double-width slot. |
- if (kind == DOUBLE_REGISTERS) { |
- spill_slot_count_++; |
- spill_slot_count_ |= 1; |
- num_double_slots_++; |
+ switch (kind) { |
+ case GENERAL_REGISTERS: return spill_slot_count_++; |
+ case DOUBLE_REGISTERS: { |
+ // Skip a slot if for a double-width slot. |
+ spill_slot_count_++; |
+ spill_slot_count_ |= 1; |
+ num_double_slots_++; |
+ return spill_slot_count_++; |
+ } |
+ case FLOAT32x4_REGISTERS: |
+ case INT32x4_REGISTERS: { |
+ // Skip three slots if for a double-width slot. |
+ spill_slot_count_ += 3; |
+ num_double_slots_++; // for dynamic frame alignment |
+ return spill_slot_count_++; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return -1; |
} |
- return spill_slot_count_++; |
} |
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) { |
int index = GetNextSpillIndex(kind); |
- if (kind == DOUBLE_REGISTERS) { |
- return LDoubleStackSlot::Create(index, zone()); |
- } else { |
- ASSERT(kind == GENERAL_REGISTERS); |
- return LStackSlot::Create(index, zone()); |
+ switch (kind) { |
+ case GENERAL_REGISTERS: return LStackSlot::Create(index, zone()); |
+ case DOUBLE_REGISTERS: return LDoubleStackSlot::Create(index, zone()); |
+ case FLOAT32x4_REGISTERS: return LFloat32x4StackSlot::Create(index, zone()); |
+ case INT32x4_REGISTERS: return LInt32x4StackSlot::Create(index, zone()); |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
} |
} |
@@ -1984,6 +2000,16 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { |
LOperand* temp = TempRegister(); |
LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp); |
return AssignEnvironment(DefineAsRegister(res)); |
+ } else if (to.IsFloat32x4()) { |
+ LOperand* value = UseRegister(instr->value()); |
+ LOperand* temp = TempRegister(); |
+ LTaggedToFloat32x4* res = new(zone()) LTaggedToFloat32x4(value, temp); |
+ return AssignEnvironment(DefineAsRegister(res)); |
+ } else if (to.IsInt32x4()) { |
+ LOperand* value = UseRegister(instr->value()); |
+ LOperand* temp = TempRegister(); |
+ LTaggedToInt32x4* res = new(zone()) LTaggedToInt32x4(value, temp); |
+ return AssignEnvironment(DefineAsRegister(res)); |
} else if (to.IsSmi()) { |
HValue* val = instr->value(); |
LOperand* value = UseRegister(val); |
@@ -2067,6 +2093,27 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { |
new(zone()) LInteger32ToDouble(Use(instr->value()))); |
} |
} |
+ } else if (from.IsFloat32x4()) { |
+ ASSERT(to.IsTagged()); |
+ info()->MarkAsDeferredCalling(); |
+ LOperand* value = UseRegister(instr->value()); |
+ LOperand* temp = TempRegister(); |
+ |
+ // Make sure that temp and result_temp are different registers. |
+ LUnallocated* result_temp = TempRegister(); |
+ LFloat32x4ToTagged* result = |
+ new(zone()) LFloat32x4ToTagged(value, temp); |
+ return AssignPointerMap(Define(result, result_temp)); |
+ } else if (from.IsInt32x4()) { |
+ ASSERT(to.IsTagged()); |
+ info()->MarkAsDeferredCalling(); |
+ LOperand* value = UseRegister(instr->value()); |
+ LOperand* temp = TempRegister(); |
+ |
+ // Make sure that temp and result_temp are different registers. |
+ LUnallocated* result_temp = TempRegister(); |
+ LInt32x4ToTagged* result = new(zone()) LInt32x4ToTagged(value, temp); |
+ return AssignPointerMap(Define(result, result_temp)); |
} |
UNREACHABLE(); |
return NULL; |
@@ -2283,19 +2330,33 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { |
: UseRegisterOrConstantAtStart(instr->key()); |
LLoadKeyed* result = NULL; |
+ bool load_128bits_without_sse2 = |
+ ExternalArrayOpRequiresSpecialHandling(elements_kind); |
if (!instr->is_external()) { |
LOperand* obj = UseRegisterAtStart(instr->elements()); |
- result = new(zone()) LLoadKeyed(obj, key); |
+ result = new(zone()) LLoadKeyed(obj, key, NULL); |
} else { |
ASSERT( |
(instr->representation().IsInteger32() && |
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) && |
- (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || |
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS) && |
+ (elements_kind != EXTERNAL_FLOAT32x4_ELEMENTS) && |
+ (elements_kind != EXTERNAL_INT32x4_ELEMENTS)) || |
(instr->representation().IsDouble() && |
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || |
- (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); |
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))) || |
+ (CpuFeatures::IsSupported(SSE2) ? |
+ instr->representation().IsFloat32x4() : |
+ instr->representation().IsTagged() && |
+ elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS) || |
+ (CpuFeatures::IsSupported(SSE2) ? |
+ instr->representation().IsInt32x4() : |
+ instr->representation().IsTagged() && |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS)); |
LOperand* external_pointer = UseRegister(instr->elements()); |
- result = new(zone()) LLoadKeyed(external_pointer, key); |
+ result = new(zone()) LLoadKeyed(external_pointer, key, |
+ load_128bits_without_sse2 ? TempRegister() : NULL); |
+ if (load_128bits_without_sse2) info()->MarkAsDeferredCalling(); |
} |
DefineAsRegister(result); |
@@ -2303,7 +2364,8 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { |
(elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS); |
// An unsigned int array load might overflow and cause a deopt, make sure it |
// has an environment. |
- return can_deoptimize ? AssignEnvironment(result) : result; |
+ return can_deoptimize ? AssignEnvironment(result) |
+ : load_128bits_without_sse2 ? AssignPointerMap(result) : result; |
} |
@@ -2350,7 +2412,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { |
LOperand* val = NULL; |
val = UseRegisterAtStart(instr->value()); |
LOperand* key = UseRegisterOrConstantAtStart(instr->key()); |
- return new(zone()) LStoreKeyed(object, key, val); |
+ return new(zone()) LStoreKeyed(object, key, val, NULL); |
} else { |
ASSERT(instr->value()->representation().IsSmiOrTagged()); |
bool needs_write_barrier = instr->NeedsWriteBarrier(); |
@@ -2365,7 +2427,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { |
val = UseRegisterOrConstantAtStart(instr->value()); |
key = UseRegisterOrConstantAtStart(instr->key()); |
} |
- return new(zone()) LStoreKeyed(obj, key, val); |
+ return new(zone()) LStoreKeyed(obj, key, val, NULL); |
} |
} |
@@ -2373,10 +2435,19 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { |
ASSERT( |
(instr->value()->representation().IsInteger32() && |
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) && |
- (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || |
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS) && |
+ (elements_kind != EXTERNAL_FLOAT32x4_ELEMENTS)) || |
(instr->value()->representation().IsDouble() && |
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || |
- (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); |
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))) || |
+ (CpuFeatures::IsSupported(SSE2) |
+ ? instr->value()->representation().IsFloat32x4() |
+ : instr->value()->representation().IsTagged() && |
+ elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS) || |
+ (CpuFeatures::IsSupported(SSE2) |
+ ? instr->value()->representation().IsInt32x4() |
+ : instr->value()->representation().IsTagged() && |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS)); |
ASSERT(instr->elements()->representation().IsExternal()); |
LOperand* external_pointer = UseRegister(instr->elements()); |
@@ -2386,9 +2457,12 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { |
LOperand* key = clobbers_key |
? UseTempRegister(instr->key()) |
: UseRegisterOrConstantAtStart(instr->key()); |
- return new(zone()) LStoreKeyed(external_pointer, |
- key, |
- val); |
+ bool store_128bits_without_sse2 = |
+ ExternalArrayOpRequiresSpecialHandling(elements_kind); |
+ LStoreKeyed* result = |
+ new(zone()) LStoreKeyed(external_pointer, key, val, |
+ store_128bits_without_sse2 ? TempRegister() : NULL); |
+ return store_128bits_without_sse2 ? AssignEnvironment(result) : result; |
} |
@@ -2792,6 +2866,282 @@ LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { |
} |
+const char* LNullarySIMDOperation::Mnemonic() const { |
+ switch (op()) { |
+ case kFloat32x4Zero: return "float32x4-zero"; |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+LInstruction* LChunkBuilder::DoNullarySIMDOperation( |
+ HNullarySIMDOperation* instr) { |
+ LNullarySIMDOperation* result = |
+ new(zone()) LNullarySIMDOperation(instr->op()); |
+ switch (instr->op()) { |
+ case kFloat32x4Zero: |
+ return DefineAsRegister(result); |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+const char* LUnarySIMDOperation::Mnemonic() const { |
+ switch (op()) { |
+ case kFloat32x4OrInt32x4Change: return "float32x4_int32x4-change"; |
+ case kSIMDAbs: return "simd-abs"; |
+ case kSIMDNeg: return "simd-neg"; |
+ case kSIMDNegU32: return "simd-negu32"; |
+ case kSIMDReciprocal: return "simd-reciprocal"; |
+ case kSIMDReciprocalSqrt: return "simd-reciprocalSqrt"; |
+ case kSIMDSqrt: return "simd-sqrt"; |
+ case kSIMDBitsToFloat32x4: return "simd-bitsToFloat32x4"; |
+ case kSIMDToFloat32x4: return "simd-toFloat32x4"; |
+ case kSIMDBitsToInt32x4: return "simd-bitsToInt32x4"; |
+ case kSIMDToInt32x4: return "simd-toInt32x4"; |
+ case kFloat32x4Splat: return "float32x4-splat"; |
+ case kInt32x4Splat: return "int32x4-splat"; |
+ case kFloat32x4SignMask: return "float32x4-signMask"; |
+ case kFloat32x4X: return "float32x4-x"; |
+ case kFloat32x4Y: return "float32x4-y"; |
+ case kFloat32x4Z: return "float32x4-z"; |
+ case kFloat32x4W: return "float32x4-w"; |
+ case kInt32x4SignMask: return "int32x4-signMask"; |
+ case kInt32x4X: return "int32x4-x"; |
+ case kInt32x4Y: return "int32x4-y"; |
+ case kInt32x4Z: return "int32x4-z"; |
+ case kInt32x4W: return "int32x4-w"; |
+ case kInt32x4FlagX: return "int32x4-flagX"; |
+ case kInt32x4FlagY: return "int32x4-flagY"; |
+ case kInt32x4FlagZ: return "int32x4-flagZ"; |
+ case kInt32x4FlagW: return "int32x4-flagW"; |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+LInstruction* LChunkBuilder::DoUnarySIMDOperation(HUnarySIMDOperation* instr) { |
+ LOperand* input = UseRegisterAtStart(instr->value()); |
+ LUnarySIMDOperation* result = |
+ new(zone()) LUnarySIMDOperation(input, instr->op()); |
+ switch (instr->op()) { |
+ case kFloat32x4OrInt32x4Change: |
+ return AssignEnvironment(DefineAsRegister(result)); |
+ case kSIMDAbs: |
+ case kSIMDNeg: |
+ case kSIMDNegU32: |
+ case kSIMDReciprocal: |
+ case kSIMDReciprocalSqrt: |
+ case kSIMDSqrt: |
+ return DefineSameAsFirst(result); |
+ case kSIMDBitsToFloat32x4: |
+ case kSIMDToFloat32x4: |
+ case kSIMDBitsToInt32x4: |
+ case kSIMDToInt32x4: |
+ case kFloat32x4Splat: |
+ case kInt32x4Splat: |
+ case kFloat32x4SignMask: |
+ case kFloat32x4X: |
+ case kFloat32x4Y: |
+ case kFloat32x4Z: |
+ case kFloat32x4W: |
+ case kInt32x4SignMask: |
+ case kInt32x4X: |
+ case kInt32x4Y: |
+ case kInt32x4Z: |
+ case kInt32x4W: |
+ case kInt32x4FlagX: |
+ case kInt32x4FlagY: |
+ case kInt32x4FlagZ: |
+ case kInt32x4FlagW: |
+ return DefineAsRegister(result); |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+const char* LBinarySIMDOperation::Mnemonic() const { |
+ switch (op()) { |
+ case kSIMDAdd: return "simd-add"; |
+ case kSIMDSub: return "simd-sub"; |
+ case kSIMDMul: return "simd-mul"; |
+ case kSIMDDiv: return "simd-mul"; |
+ case kSIMDMin: return "simd-min"; |
+ case kSIMDMax: return "simd-max"; |
+ case kSIMDScale: return "simd-scale"; |
+ case kSIMDAnd: return "simd-and"; |
+ case kSIMDOr: return "simd-or"; |
+ case kSIMDXor: return "simd-xor"; |
+ case kSIMDAddU32: return "simd-addu32"; |
+ case kSIMDSubU32: return "simd-subu32"; |
+ case kSIMDMulU32: return "simd-mulu32"; |
+ case kSIMDShuffle: return "simd-shuffle"; |
+ case kSIMDShuffleU32: return "simd-shuffleu32"; |
+ case kSIMDLessThan: return "simd-lessThan"; |
+ case kSIMDLessThanOrEqual: return "simd-lessThanOrEqual"; |
+ case kSIMDEqual: return "simd-equal"; |
+ case kSIMDNotEqual: return "simd-notEqual"; |
+ case kSIMDGreaterThanOrEqual: return "simd-greaterThanOrEqual"; |
+ case kSIMDGreaterThan: return "simd-greaterThan"; |
+ case kSIMDWithX: return "simd-withX"; |
+ case kSIMDWithY: return "simd-withY"; |
+ case kSIMDWithZ: return "simd-withZ"; |
+ case kSIMDWithW: return "simd-withW"; |
+ case kSIMDWithXu32: return "simd-withXu32"; |
+ case kSIMDWithYu32: return "simd-withYu32"; |
+ case kSIMDWithZu32: return "simd-withZu32"; |
+ case kSIMDWithWu32: return "simd-withWu32"; |
+ case kSIMDWithFlagX: return "simd-withFlagX"; |
+ case kSIMDWithFlagY: return "simd-withFlagY"; |
+ case kSIMDWithFlagZ: return "simd-withFlagZ"; |
+ case kSIMDWithFlagW: return "simd-withFlagW"; |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+LInstruction* LChunkBuilder::DoBinarySIMDOperation( |
+ HBinarySIMDOperation* instr) { |
+ switch (instr->op()) { |
+ case kSIMDAdd: |
+ case kSIMDSub: |
+ case kSIMDMul: |
+ case kSIMDDiv: |
+ case kSIMDMin: |
+ case kSIMDMax: |
+ case kSIMDScale: |
+ case kSIMDAnd: |
+ case kSIMDOr: |
+ case kSIMDXor: |
+ case kSIMDAddU32: |
+ case kSIMDSubU32: |
+ case kSIMDMulU32: |
+ case kSIMDWithX: |
+ case kSIMDWithY: |
+ case kSIMDWithZ: |
+ case kSIMDWithW: |
+ case kSIMDWithXu32: |
+ case kSIMDWithYu32: |
+ case kSIMDWithZu32: |
+ case kSIMDWithWu32: |
+ case kSIMDWithFlagX: |
+ case kSIMDWithFlagY: |
+ case kSIMDWithFlagZ: |
+ case kSIMDWithFlagW: { |
+ LOperand* left = UseRegisterAtStart(instr->left()); |
+ LOperand* right = UseRegisterAtStart(instr->right()); |
+ LBinarySIMDOperation* result = |
+ new(zone()) LBinarySIMDOperation(left, right, instr->op()); |
+ if (instr->op() == kSIMDWithFlagX || instr->op() == kSIMDWithFlagY || |
+ instr->op() == kSIMDWithFlagZ || instr->op() == kSIMDWithFlagW) { |
+ return AssignEnvironment(DefineSameAsFirst(result)); |
+ } else { |
+ return DefineSameAsFirst(result); |
+ } |
+ } |
+ case kSIMDShuffle: |
+ case kSIMDShuffleU32: { |
+ LOperand* left = UseRegisterAtStart(instr->left()); |
+ LOperand* right = UseOrConstant(instr->right()); |
+ LBinarySIMDOperation* result = |
+ new(zone()) LBinarySIMDOperation(left, right, instr->op()); |
+ return AssignEnvironment(DefineSameAsFirst(result)); |
+ } |
+ case kSIMDLessThan: |
+ case kSIMDLessThanOrEqual: |
+ case kSIMDEqual: |
+ case kSIMDNotEqual: |
+ case kSIMDGreaterThanOrEqual: |
+ case kSIMDGreaterThan: { |
+ LOperand* left = UseRegisterAtStart(instr->left()); |
+ LOperand* right = UseRegisterAtStart(instr->right()); |
+ LBinarySIMDOperation* result = |
+ new(zone()) LBinarySIMDOperation(left, right, instr->op()); |
+ return DefineAsRegister(result); |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+const char* LTernarySIMDOperation::Mnemonic() const { |
+ switch (op()) { |
+ case kSIMDSelect: return "simd-select"; |
+ case kSIMDShuffleMix: return "simd-shuffleMix"; |
+ case kSIMDClamp: return "simd-clamp"; |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+LInstruction* LChunkBuilder::DoTernarySIMDOperation( |
+ HTernarySIMDOperation* instr) { |
+ LOperand* first = UseRegisterAtStart(instr->first()); |
+ LOperand* second = UseRegisterAtStart(instr->second()); |
+ LOperand* third = instr->op() == kSIMDShuffleMix |
+ ? UseOrConstant(instr->third()) |
+ : UseRegisterAtStart(instr->third()); |
+ LTernarySIMDOperation* result = |
+ new(zone()) LTernarySIMDOperation(first, second, third, instr->op()); |
+ switch (instr->op()) { |
+ case kSIMDSelect: { |
+ return DefineAsRegister(result); |
+ } |
+ case kSIMDShuffleMix: { |
+ return AssignEnvironment(DefineSameAsFirst(result)); |
+ } |
+ case kSIMDClamp: { |
+ return DefineSameAsFirst(result); |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+const char* LQuarternarySIMDOperation::Mnemonic() const { |
+ switch (op()) { |
+ case kFloat32x4Constructor: return "float32x4-constructor"; |
+ case kInt32x4Constructor: return "int32x4-constructor"; |
+ case kInt32x4Bool: return "int32x4-bool"; |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
+LInstruction* LChunkBuilder::DoQuarternarySIMDOperation( |
+ HQuarternarySIMDOperation* instr) { |
+ LOperand* x = UseRegisterAtStart(instr->x()); |
+ LOperand* y = UseRegisterAtStart(instr->y()); |
+ LOperand* z = UseRegisterAtStart(instr->z()); |
+ LOperand* w = UseRegisterAtStart(instr->w()); |
+ LQuarternarySIMDOperation* result = |
+ new(zone()) LQuarternarySIMDOperation(x, y, z, w, instr->op()); |
+ if (instr->op() == kInt32x4Bool) { |
+ return AssignEnvironment(DefineAsRegister(result)); |
+ } else { |
+ return DefineAsRegister(result); |
+ } |
+} |
+ |
+ |
} } // namespace v8::internal |
#endif // V8_TARGET_ARCH_IA32 |