Index: src/x64/lithium-x64.cc |
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc |
index 78bc5bb7089322c6e93a574b137ceb53d0f72e08..426456b2ee91b64905729fb35557d0b13840e9e7 100644 |
--- a/src/x64/lithium-x64.cc |
+++ b/src/x64/lithium-x64.cc |
@@ -354,6 +354,19 @@ void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { |
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) { |
+ switch (kind) { |
+ case GENERAL_REGISTERS: return spill_slot_count_++; |
+ case DOUBLE_REGISTERS: return spill_slot_count_++; |
+ case FLOAT32x4_REGISTERS: |
+ case INT32x4_REGISTERS: { |
+ spill_slot_count_++; |
+ return spill_slot_count_++; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ return -1; |
+ } |
+ |
return spill_slot_count_++; |
} |
@@ -363,11 +376,14 @@ LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) { |
// Alternatively, at some point, start using half-size |
// stack slots for int32 values. |
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; |
} |
} |
@@ -1276,6 +1292,282 @@ LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* 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); |
+ } |
+} |
+ |
+ |
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) { |
ASSERT(instr->key()->representation().IsTagged()); |
LOperand* context = UseFixed(instr->context(), rsi); |
@@ -1868,6 +2160,14 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { |
LOperand* value = UseRegister(instr->value()); |
LNumberUntagD* res = new(zone()) LNumberUntagD(value); |
return AssignEnvironment(DefineAsRegister(res)); |
+ } else if (to.IsFloat32x4()) { |
+ LOperand* value = UseRegister(instr->value()); |
+ LTaggedToFloat32x4* res = new(zone()) LTaggedToFloat32x4(value); |
+ return AssignEnvironment(DefineAsRegister(res)); |
+ } else if (to.IsInt32x4()) { |
+ LOperand* value = UseRegister(instr->value()); |
+ LTaggedToInt32x4* res = new(zone()) LTaggedToInt32x4(value); |
+ return AssignEnvironment(DefineAsRegister(res)); |
} else if (to.IsSmi()) { |
HValue* val = instr->value(); |
LOperand* value = UseRegister(val); |
@@ -1951,6 +2251,26 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { |
return DefineAsRegister(new(zone()) LInteger32ToDouble(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; |
@@ -2163,10 +2483,16 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { |
ASSERT( |
(instr->representation().IsInteger32() && |
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) && |
+ (elements_kind != EXTERNAL_FLOAT32x4_ELEMENTS) && |
+ (elements_kind != EXTERNAL_INT32x4_ELEMENTS) && |
(elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || |
(instr->representation().IsDouble() && |
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || |
- (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); |
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))) || |
+ (instr->representation().IsFloat32x4() && |
+ elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS) || |
+ (instr->representation().IsInt32x4() && |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS)); |
LOperand* external_pointer = UseRegister(instr->elements()); |
result = new(zone()) LLoadKeyed(external_pointer, key); |
} |
@@ -2223,10 +2549,16 @@ 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) && |
+ (elements_kind != EXTERNAL_INT32x4_ELEMENTS)) || |
(instr->value()->representation().IsDouble() && |
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || |
- (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); |
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))) || |
+ (instr->value()->representation().IsFloat32x4() && |
+ elements_kind == EXTERNAL_FLOAT32x4_ELEMENTS) || |
+ (instr->value()->representation().IsInt32x4() && |
+ elements_kind == EXTERNAL_INT32x4_ELEMENTS)); |
ASSERT(instr->elements()->representation().IsExternal()); |
bool val_is_temp_register = |
elements_kind == EXTERNAL_PIXEL_ELEMENTS || |