Index: runtime/vm/assembler_arm_test.cc |
=================================================================== |
--- runtime/vm/assembler_arm_test.cc (revision 34252) |
+++ runtime/vm/assembler_arm_test.cc (working copy) |
@@ -1817,6 +1817,188 @@ |
} |
+ASSEMBLER_TEST_GENERATE(Vshlqu64, assembler) { |
+ if (TargetCPUFeatures::neon_supported()) { |
+ Label fail; |
+ __ LoadImmediate(R1, 21); |
+ __ LoadImmediate(R0, 1); |
+ __ vmovsr(S0, R1); |
+ __ vmovsr(S2, R1); |
+ __ vmovsr(S4, R0); |
+ __ vmovsr(S6, R0); |
+ |
+ __ vshlqu(kWordPair, Q2, Q0, Q1); |
+ |
+ __ vmovrs(R0, S8); |
+ __ vmovrs(R1, S10); |
+ __ CompareImmediate(R0, 42); |
+ __ LoadImmediate(R0, 0); |
+ __ b(&fail, NE); |
+ __ CompareImmediate(R1, 42); |
+ __ LoadImmediate(R0, 0); |
+ __ b(&fail, NE); |
+ |
+ __ LoadImmediate(R0, 1); |
+ __ Bind(&fail); |
+ __ bx(LR); |
+ } else { |
+ __ LoadImmediate(R0, 1); |
+ __ bx(LR); |
+ } |
+} |
+ |
+ |
+ASSEMBLER_TEST_RUN(Vshlqu64, test) { |
+ EXPECT(test != NULL); |
+ typedef int (*Tst)(); |
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry())); |
+} |
+ |
+ |
+ASSEMBLER_TEST_GENERATE(Vshlqi64, assembler) { |
+ if (TargetCPUFeatures::neon_supported()) { |
+ Label fail; |
+ __ LoadImmediate(R1, -84); |
+ __ LoadImmediate(R0, -1); |
+ __ vmovdrr(D0, R1, R0); |
+ __ vmovdrr(D1, R1, R0); |
+ __ vmovsr(S4, R0); |
+ __ vmovsr(S6, R0); |
+ |
+ __ vshlqi(kWordPair, Q2, Q0, Q1); |
+ |
+ __ vmovrs(R0, S8); |
+ __ vmovrs(R1, S10); |
+ __ CompareImmediate(R0, -42); |
+ __ LoadImmediate(R0, 0); |
+ __ b(&fail, NE); |
+ __ CompareImmediate(R1, -42); |
+ __ LoadImmediate(R0, 0); |
+ __ b(&fail, NE); |
+ |
+ __ LoadImmediate(R0, 1); |
+ __ Bind(&fail); |
+ __ bx(LR); |
+ } else { |
+ __ LoadImmediate(R0, 1); |
+ __ bx(LR); |
+ } |
+} |
+ |
+ |
+ASSEMBLER_TEST_RUN(Vshlqi64, test) { |
+ EXPECT(test != NULL); |
+ typedef int (*Tst)(); |
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry())); |
+} |
+ |
+ |
+ASSEMBLER_TEST_GENERATE(Mint_shl_ok, assembler) { |
+ const QRegister value = Q0; |
+ const QRegister temp = Q1; |
+ const QRegister out = Q2; |
+ const Register shift = R1; |
+ const DRegister dtemp0 = EvenDRegisterOf(temp); |
+ const SRegister stemp0 = EvenSRegisterOf(dtemp0); |
+ const DRegister dout0 = EvenDRegisterOf(out); |
+ const SRegister sout0 = EvenSRegisterOf(dout0); |
+ const SRegister sout1 = OddSRegisterOf(dout0); |
+ Label fail; |
+ |
+ // Initialize. |
+ __ veorq(value, value, value); |
+ __ veorq(temp, temp, temp); |
+ __ veorq(out, out, out); |
+ __ LoadImmediate(shift, 32); |
+ __ LoadImmediate(R2, 1 << 7); |
+ __ vmovsr(S0, R2); |
+ |
+ __ vmovsr(stemp0, shift); // Move the shift into the low S register. |
+ __ vshlqu(kWordPair, out, value, temp); |
+ |
+ // check for overflow by shifting back and comparing. |
+ __ rsb(shift, shift, ShifterOperand(0)); |
+ __ vmovsr(stemp0, shift); |
+ __ vshlqi(kWordPair, temp, out, temp); |
+ __ vceqqi(kWord, out, temp, value); |
+ // Low 64 bits of temp should be all 1's, otherwise temp != value and |
+ // we deopt. |
+ __ vmovrs(shift, sout0); |
+ __ CompareImmediate(shift, -1); |
+ __ b(&fail, NE); |
+ __ vmovrs(shift, sout1); |
+ __ CompareImmediate(shift, -1); |
+ __ b(&fail, NE); |
+ |
+ __ LoadImmediate(R0, 1); |
+ __ bx(LR); |
+ |
+ __ Bind(&fail); |
+ __ LoadImmediate(R0, 0); |
+ __ bx(LR); |
+} |
+ |
+ |
+ASSEMBLER_TEST_RUN(Mint_shl_ok, test) { |
+ EXPECT(test != NULL); |
+ typedef int (*Tst)(); |
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry())); |
+} |
+ |
+ |
+ASSEMBLER_TEST_GENERATE(Mint_shl_overflow, assembler) { |
+ const QRegister value = Q0; |
+ const QRegister temp = Q1; |
+ const QRegister out = Q2; |
+ const Register shift = R1; |
+ const DRegister dtemp0 = EvenDRegisterOf(temp); |
+ const SRegister stemp0 = EvenSRegisterOf(dtemp0); |
+ const DRegister dout0 = EvenDRegisterOf(out); |
+ const SRegister sout0 = EvenSRegisterOf(dout0); |
+ const SRegister sout1 = OddSRegisterOf(dout0); |
+ Label fail; |
+ |
+ // Initialize. |
+ __ veorq(value, value, value); |
+ __ veorq(temp, temp, temp); |
+ __ veorq(out, out, out); |
+ __ LoadImmediate(shift, 60); |
+ __ LoadImmediate(R2, 1 << 7); |
+ __ vmovsr(S0, R2); |
+ |
+ __ vmovsr(stemp0, shift); // Move the shift into the low S register. |
+ __ vshlqu(kWordPair, out, value, temp); |
+ |
+ // check for overflow by shifting back and comparing. |
+ __ rsb(shift, shift, ShifterOperand(0)); |
+ __ vmovsr(stemp0, shift); |
+ __ vshlqi(kWordPair, temp, out, temp); |
+ __ vceqqi(kWord, out, temp, value); |
+ // Low 64 bits of temp should be all 1's, otherwise temp != value and |
+ // we deopt. |
+ __ vmovrs(shift, sout0); |
+ __ CompareImmediate(shift, -1); |
+ __ b(&fail, NE); |
+ __ vmovrs(shift, sout1); |
+ __ CompareImmediate(shift, -1); |
+ __ b(&fail, NE); |
+ |
+ __ LoadImmediate(R0, 0); |
+ __ bx(LR); |
+ |
+ __ Bind(&fail); |
+ __ LoadImmediate(R0, 1); |
+ __ bx(LR); |
+} |
+ |
+ |
+ASSEMBLER_TEST_RUN(Mint_shl_overflow, test) { |
+ EXPECT(test != NULL); |
+ typedef int (*Tst)(); |
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry())); |
+} |
+ |
+ |
ASSEMBLER_TEST_GENERATE(Vsubqi8, assembler) { |
if (TargetCPUFeatures::neon_supported()) { |
__ mov(R0, ShifterOperand(1)); |
@@ -2596,6 +2778,28 @@ |
} |
+ASSEMBLER_TEST_GENERATE(Vmvnq, assembler) { |
+ if (TargetCPUFeatures::neon_supported()) { |
+ __ LoadImmediate(R1, 42); // R1 <- 42. |
+ __ vmovsr(S2, R1); // S2 <- R1. |
+ __ vmvnq(Q1, Q0); // Q1 <- ~Q0. |
+ __ vmvnq(Q2, Q1); // Q2 <- ~Q1. |
+ __ vmovrs(R0, S10); // Now R0 should be 42 again. |
+ __ bx(LR); |
+ } else { |
+ __ LoadImmediate(R0, 42); |
+ __ bx(LR); |
+ } |
+} |
+ |
+ |
+ASSEMBLER_TEST_RUN(Vmvnq, test) { |
+ EXPECT(test != NULL); |
+ typedef int (*Tst)(); |
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry())); |
+} |
+ |
+ |
ASSEMBLER_TEST_GENERATE(Vdupb, assembler) { |
if (TargetCPUFeatures::neon_supported()) { |
__ LoadImmediate(R0, 0x00000000); |