+void LCodeGen::DoNullarySIMDOperation(LNullarySIMDOperation* instr) {
+ switch (instr->op()) {
+ case kFloat32x4Zero: {
+ XMMRegister result_reg = ToFloat32x4Register(instr->result());
+ __ xorps(result_reg, result_reg);
+ return;
+ }
+ case kInt32x4Zero: {
+ XMMRegister result_reg = ToInt32x4Register(instr->result());
+ __ xorps(result_reg, result_reg);
+ return;
+ }
+ default:
+ UNREACHABLE();
+ return;
+ }
+}
+
+
+void LCodeGen::DoUnarySIMDOperation(LUnarySIMDOperation* instr) {
+ uint8_t select = 0;
+ switch (instr->op()) {
+ case kSIMD128Change: {
+ Comment(";;; deoptimize: can not perform representation change"
+ "for float32x4 or int32x4");
+ DeoptimizeIf(no_condition, instr->environment());
+ return;
+ }
+ case kFloat32x4Abs:
+ case kFloat32x4Neg:
+ case kFloat32x4Reciprocal:
+ case kFloat32x4ReciprocalSqrt:
+ case kFloat32x4Sqrt: {
+ ASSERT(instr->value()->Equals(instr->result()));
+ ASSERT(instr->hydrogen()->value()->representation().IsFloat32x4());
+ XMMRegister input_reg = ToFloat32x4Register(instr->value());
+ switch (instr->op()) {
+ case kFloat32x4Abs:
+ __ absps(input_reg);
+ break;
+ case kFloat32x4Neg:
+ __ negateps(input_reg);
+ break;
+ case kFloat32x4Reciprocal:
+ __ rcpps(input_reg, input_reg);
+ break;
+ case kFloat32x4ReciprocalSqrt:
+ __ rsqrtps(input_reg, input_reg);
+ break;
+ case kFloat32x4Sqrt:
+ __ sqrtps(input_reg, input_reg);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ }
+ case kInt32x4Not:
+ case kInt32x4Neg: {
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4());
+ XMMRegister input_reg = ToInt32x4Register(instr->value());
+ switch (instr->op()) {
+ case kInt32x4Not:
+ __ notps(input_reg);
+ break;
+ case kInt32x4Neg:
+ __ pnegd(input_reg);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ }
+ case kFloat32x4BitsToInt32x4:
+ case kFloat32x4ToInt32x4: {
+ ASSERT(instr->hydrogen()->value()->representation().IsFloat32x4());
+ XMMRegister input_reg = ToFloat32x4Register(instr->value());
+ XMMRegister result_reg = ToInt32x4Register(instr->result());
+ if (instr->op() == kFloat32x4BitsToInt32x4) {
+ if (!result_reg.is(input_reg)) {
+ __ movaps(result_reg, input_reg);
+ }
+ } else {
+ ASSERT(instr->op() == kFloat32x4ToInt32x4);
+ __ cvtps2dq(result_reg, input_reg);
+ }
+ return;
+ }
+ case kInt32x4BitsToFloat32x4:
+ case kInt32x4ToFloat32x4: {
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4());
+ XMMRegister input_reg = ToInt32x4Register(instr->value());
+ XMMRegister result_reg = ToFloat32x4Register(instr->result());
+ if (instr->op() == kInt32x4BitsToFloat32x4) {
+ if (!result_reg.is(input_reg)) {
+ __ movaps(result_reg, input_reg);
+ }
+ } else {
+ ASSERT(instr->op() == kInt32x4ToFloat32x4);
+ __ cvtdq2ps(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 kInt32x4GetSignMask: {
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4());
+ XMMRegister input_reg = ToInt32x4Register(instr->value());
+ Register result = ToRegister(instr->result());
+ __ movmskps(result, input_reg);
+ return;
+ }
+ case kFloat32x4GetSignMask: {
+ ASSERT(instr->hydrogen()->value()->representation().IsFloat32x4());
+ XMMRegister input_reg = ToFloat32x4Register(instr->value());
+ Register result = ToRegister(instr->result());
+ __ movmskps(result, input_reg);
+ return;
+ }
+ case kFloat32x4GetW:
+ select++;
+ case kFloat32x4GetZ:
+ select++;
+ case kFloat32x4GetY:
+ select++;
+ case kFloat32x4GetX: {
+ 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 kInt32x4GetX:
+ case kInt32x4GetY:
+ case kInt32x4GetZ:
+ case kInt32x4GetW:
+ case kInt32x4GetFlagX:
+ case kInt32x4GetFlagY:
+ case kInt32x4GetFlagZ:
+ case kInt32x4GetFlagW: {
+ ASSERT(instr->hydrogen()->value()->representation().IsInt32x4());
+ bool flag = false;
+ switch (instr->op()) {
+ case kInt32x4GetFlagX:
+ flag = true;
+ case kInt32x4GetX:
+ break;
+ case kInt32x4GetFlagY:
+ flag = true;
+ case kInt32x4GetY:
+ select = 0x1;
+ break;
+ case kInt32x4GetFlagZ:
+ flag = true;
+ case kInt32x4GetZ:
+ select = 0x2;
+ break;
+ case kInt32x4GetFlagW:
+ flag = true;
+ case kInt32x4GetW:
+ 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;
+ __ testl(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) {
+ uint8_t imm8 = 0; // for with operation
+ switch (instr->op()) {
+ case kFloat32x4Add:
+ case kFloat32x4Sub:
+ case kFloat32x4Mul:
+ case kFloat32x4Div:
+ case kFloat32x4Min:
+ case kFloat32x4Max: {
+ 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 kFloat32x4Add:
+ __ addps(left_reg, right_reg);
+ break;
+ case kFloat32x4Sub:
+ __ subps(left_reg, right_reg);
+ break;
+ case kFloat32x4Mul:
+ __ mulps(left_reg, right_reg);
+ break;
+ case kFloat32x4Div:
+ __ divps(left_reg, right_reg);
+ break;
+ case kFloat32x4Min:
+ __ minps(left_reg, right_reg);
+ break;
+ case kFloat32x4Max:
+ __ maxps(left_reg, right_reg);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ }
+ case kFloat32x4Scale: {
+ 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 kFloat32x4Shuffle: {
+ 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 kInt32x4Shuffle: {
+ 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 kInt32x4ShiftLeft:
+ case kInt32x4ShiftRight:
+ case kInt32x4ShiftRightArithmetic: {
+ 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 shift = static_cast<uint8_t>(value & 0xFF);
+ XMMRegister left_reg = ToInt32x4Register(instr->left());
+ switch (instr->op()) {
+ case kInt32x4ShiftLeft:
+ __ pslld(left_reg, shift);
+ break;
+ case kInt32x4ShiftRight:
+ __ psrld(left_reg, shift);
+ break;
+ case kInt32x4ShiftRightArithmetic:
+ __ psrad(left_reg, shift);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return;
+ } else {
+ XMMRegister left_reg = ToInt32x4Register(instr->left());
+ Register shift = ToRegister(instr->right());
+ XMMRegister xmm_scratch = double_scratch0();
+ __ movd(xmm_scratch, shift);
+ switch (instr->op()) {
+ case kInt32x4ShiftLeft:
+ __ pslld(left_reg, xmm_scratch);
+ break;
+ case kInt32x4ShiftRight:
+ __ psrld(left_reg, xmm_scratch);
+ break;
+ case kInt32x4ShiftRightArithmetic:
+ __ psrad(left_reg, xmm_scratch);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return;
+ }
+ }
+ case kFloat32x4LessThan:
+ case kFloat32x4LessThanOrEqual:
+ case kFloat32x4Equal:
+ case kFloat32x4NotEqual:
+ case kFloat32x4GreaterThanOrEqual:
+ case kFloat32x4GreaterThan: {
+ 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 kFloat32x4LessThan:
+ 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 kFloat32x4LessThanOrEqual:
+ 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 kFloat32x4Equal:
+ 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 kFloat32x4NotEqual:
+ 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 kFloat32x4GreaterThanOrEqual:
+ 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 kFloat32x4GreaterThan:
+ 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 kInt32x4And:
+ case kInt32x4Or:
+ case kInt32x4Xor:
+ case kInt32x4Add:
+ case kInt32x4Sub:
+ case kInt32x4Mul:
+ case kInt32x4GreaterThan:
+ case kInt32x4Equal:
+ case kInt32x4LessThan: {
+ 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 kInt32x4And:
+ __ andps(left_reg, right_reg);
+ break;
+ case kInt32x4Or:
+ __ orps(left_reg, right_reg);
+ break;
+ case kInt32x4Xor:
+ __ xorps(left_reg, right_reg);
+ break;
+ case kInt32x4Add:
+ __ paddd(left_reg, right_reg);
+ break;
+ case kInt32x4Sub:
+ __ psubd(left_reg, right_reg);
+ break;
+ case kInt32x4Mul:
+ 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);
+ __ psrldq(xmm_scratch, 4);
+ __ psrldq(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;
+ case kInt32x4GreaterThan:
+ __ pcmpgtd(left_reg, right_reg);
+ break;
+ case kInt32x4Equal:
+ __ pcmpeqd(left_reg, right_reg);
+ break;
+ case kInt32x4LessThan: {
+ XMMRegister xmm_scratch = xmm0;
+ __ movaps(xmm_scratch, right_reg);
+ __ pcmpgtd(xmm_scratch, left_reg);
+ __ movaps(left_reg, xmm_scratch);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ }
+ case kFloat32x4WithW:
+ imm8++;
+ case kFloat32x4WithZ:
+ imm8++;
+ case kFloat32x4WithY:
+ imm8++;
+ case kFloat32x4WithX: {
+ 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 {
+ __ subq(rsp, Immediate(kFloat32x4Size));
+ __ movups(Operand(rsp, 0), left_reg);
+ __ movss(Operand(rsp, imm8 * kFloatSize), xmm_scratch);
+ __ movups(left_reg, Operand(rsp, 0));
+ __ addq(rsp, Immediate(kFloat32x4Size));
+ }
+ return;
+ }
+ case kInt32x4WithW:
+ imm8++;
+ case kInt32x4WithZ:
+ imm8++;
+ case kInt32x4WithY:
+ imm8++;
+ case kInt32x4WithX: {
+ 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 {
+ __ subq(rsp, Immediate(kInt32x4Size));
+ __ movdqu(Operand(rsp, 0), left_reg);
+ __ movl(Operand(rsp, imm8 * kFloatSize), right_reg);
+ __ movdqu(left_reg, Operand(rsp, 0));
+ __ addq(rsp, Immediate(kInt32x4Size));
+ }
+ return;
+ }
+ case kInt32x4WithFlagW:
+ imm8++;
+ case kInt32x4WithFlagZ:
+ imm8++;
+ case kInt32x4WithFlagY:
+ imm8++;
+ case kInt32x4WithFlagX: {
+ 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()) {
+ __ subq(rsp, Immediate(kInt32x4Size));
+ __ movups(Operand(rsp, 0), left_reg);
+ __ CompareRoot(right_reg, Heap::kTrueValueRootIndex);
+ __ j(not_equal, &load_false_value, Label::kNear);
+ } else {
+ Comment(";;; deoptimize: other types for int32x4.withFlagX/Y/Z/W.");
+ DeoptimizeIf(no_condition, instr->environment());
+ return;
+ }
+ // load true value.
+ __ movl(Operand(rsp, imm8 * kFloatSize), Immediate(0xFFFFFFFF));
+ __ jmp(&done, Label::kNear);
+ __ bind(&load_false_value);
+ __ movl(Operand(rsp, imm8 * kFloatSize), Immediate(0x0));
+ __ bind(&done);
+ __ movups(left_reg, Operand(rsp, 0));
+ __ addq(rsp, Immediate(kInt32x4Size));
+ return;
+ }
+ default:
+ UNREACHABLE();
+ return;
+ }
+}
+
+
+void LCodeGen::DoTernarySIMDOperation(LTernarySIMDOperation* instr) {
+ switch (instr->op()) {
+ case kInt32x4Select: {
+ 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 kFloat32x4ShuffleMix: {
+ 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 kFloat32x4Clamp: {
+ 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) {
+ 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());
+ __ subq(rsp, Immediate(kFloat32x4Size));
+ __ xorps(xmm0, xmm0);
+ __ cvtsd2ss(xmm0, x_reg);
+ __ movss(Operand(rsp, 0 * kFloatSize), xmm0);
+ __ xorps(xmm0, xmm0);
+ __ cvtsd2ss(xmm0, y_reg);
+ __ movss(Operand(rsp, 1 * kFloatSize), xmm0);
+ __ xorps(xmm0, xmm0);
+ __ cvtsd2ss(xmm0, z_reg);
+ __ movss(Operand(rsp, 2 * kFloatSize), xmm0);
+ __ xorps(xmm0, xmm0);
+ __ cvtsd2ss(xmm0, w_reg);
+ __ movss(Operand(rsp, 3 * kFloatSize), xmm0);
+ __ movups(result_reg, Operand(rsp, 0 * kFloatSize));
+ __ addq(rsp, 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());
+ __ subq(rsp, Immediate(kInt32x4Size));
+ __ movl(Operand(rsp, 0 * kInt32Size), x_reg);
+ __ movl(Operand(rsp, 1 * kInt32Size), y_reg);
+ __ movl(Operand(rsp, 2 * kInt32Size), z_reg);
+ __ movl(Operand(rsp, 3 * kInt32Size), w_reg);
+ __ movups(result_reg, Operand(rsp, 0 * kInt32Size));
+ __ addq(rsp, 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;
+ __ subq(rsp, Immediate(kInt32x4Size));
+
+ __ CompareRoot(x_reg, Heap::kTrueValueRootIndex);
+ __ j(not_equal, &load_false_x, Label::kNear);
+ __ movl(Operand(rsp, 0 * kInt32Size), Immediate(-1));
+ __ jmp(&done_x, Label::kNear);
+ __ bind(&load_false_x);
+ __ movl(Operand(rsp, 0 * kInt32Size), Immediate(0x0));
+ __ bind(&done_x);
+
+ __ CompareRoot(y_reg, Heap::kTrueValueRootIndex);
+ __ j(not_equal, &load_false_y, Label::kNear);
+ __ movl(Operand(rsp, 1 * kInt32Size), Immediate(-1));
+ __ jmp(&done_y, Label::kNear);
+ __ bind(&load_false_y);
+ __ movl(Operand(rsp, 1 * kInt32Size), Immediate(0x0));
+ __ bind(&done_y);
+
+ __ CompareRoot(z_reg, Heap::kTrueValueRootIndex);
+ __ j(not_equal, &load_false_z, Label::kNear);
+ __ movl(Operand(rsp, 2 * kInt32Size), Immediate(-1));
+ __ jmp(&done_z, Label::kNear);
+ __ bind(&load_false_z);
+ __ movl(Operand(rsp, 2 * kInt32Size), Immediate(0x0));
+ __ bind(&done_z);
+
+ __ CompareRoot(w_reg, Heap::kTrueValueRootIndex);
+ __ j(not_equal, &load_false_w, Label::kNear);
+ __ movl(Operand(rsp, 3 * kInt32Size), Immediate(-1));
+ __ jmp(&done_w, Label::kNear);
+ __ bind(&load_false_w);
+ __ movl(Operand(rsp, 3 * kInt32Size), Immediate(0x0));
+ __ bind(&done_w);
+
+ __ movups(result_reg, Operand(rsp, 0));
+ __ addq(rsp, Immediate(kInt32x4Size));
+ return;
+ }
+ default:
+ UNREACHABLE();
+ return;
+ }
+}
+
+