Index: test/cctest/test-macro-assembler-mips.cc |
diff --git a/test/cctest/test-macro-assembler-mips.cc b/test/cctest/test-macro-assembler-mips.cc |
index 91ee2153153eab6bace14a4ac111243f250dd1b7..7e1ffd7872a2859ad36766e920c829345e15a1cf 100644 |
--- a/test/cctest/test-macro-assembler-mips.cc |
+++ b/test/cctest/test-macro-assembler-mips.cc |
@@ -390,14 +390,14 @@ TEST(Lsa) { |
} |
} |
-static const std::vector<uint32_t> uint32_test_values() { |
+static const std::vector<uint32_t> cvt_trunc_uint32_test_values() { |
static const uint32_t kValues[] = {0x00000000, 0x00000001, 0x00ffff00, |
0x7fffffff, 0x80000000, 0x80000001, |
0x80ffff00, 0x8fffffff, 0xffffffff}; |
return std::vector<uint32_t>(&kValues[0], &kValues[arraysize(kValues)]); |
} |
-static const std::vector<int32_t> int32_test_values() { |
+static const std::vector<int32_t> cvt_trunc_int32_test_values() { |
static const int32_t kValues[] = { |
static_cast<int32_t>(0x00000000), static_cast<int32_t>(0x00000001), |
static_cast<int32_t>(0x00ffff00), static_cast<int32_t>(0x7fffffff), |
@@ -408,13 +408,19 @@ static const std::vector<int32_t> int32_test_values() { |
} |
// Helper macros that can be used in FOR_INT32_INPUTS(i) { ... *i ... } |
-#define FOR_INPUTS(ctype, itype, var) \ |
- std::vector<ctype> var##_vec = itype##_test_values(); \ |
+#define FOR_INPUTS(ctype, itype, var, test_vector) \ |
+ std::vector<ctype> var##_vec = test_vector(); \ |
for (std::vector<ctype>::iterator var = var##_vec.begin(); \ |
var != var##_vec.end(); ++var) |
-#define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var) |
-#define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var) |
+#define FOR_ENUM_INPUTS(var, type, test_vector) \ |
+ FOR_INPUTS(enum type, type, var, test_vector) |
+#define FOR_STRUCT_INPUTS(var, type, test_vector) \ |
+ FOR_INPUTS(struct type, type, var, test_vector) |
+#define FOR_UINT32_INPUTS(var, test_vector) \ |
+ FOR_INPUTS(uint32_t, uint32, var, test_vector) |
+#define FOR_INT32_INPUTS(var, test_vector) \ |
+ FOR_INPUTS(int32_t, int32, var, test_vector) |
template <typename RET_TYPE, typename IN_TYPE, typename Func> |
RET_TYPE run_Cvt(IN_TYPE x, Func GenerateConvertInstructionFunc) { |
@@ -445,7 +451,7 @@ RET_TYPE run_Cvt(IN_TYPE x, Func GenerateConvertInstructionFunc) { |
TEST(cvt_s_w_Trunc_uw_s) { |
CcTest::InitializeVM(); |
- FOR_UINT32_INPUTS(i) { |
+ FOR_UINT32_INPUTS(i, cvt_trunc_uint32_test_values) { |
uint32_t input = *i; |
CHECK_EQ(static_cast<float>(input), |
run_Cvt<uint32_t>(input, [](MacroAssembler* masm) { |
@@ -457,7 +463,7 @@ TEST(cvt_s_w_Trunc_uw_s) { |
TEST(cvt_d_w_Trunc_w_d) { |
CcTest::InitializeVM(); |
- FOR_INT32_INPUTS(i) { |
+ FOR_INT32_INPUTS(i, cvt_trunc_int32_test_values) { |
int32_t input = *i; |
CHECK_EQ(static_cast<double>(input), |
run_Cvt<int32_t>(input, [](MacroAssembler* masm) { |
@@ -467,6 +473,342 @@ TEST(cvt_d_w_Trunc_w_d) { |
} |
} |
+static const std::vector<int32_t> overflow_int32_test_values() { |
+ static const int32_t kValues[] = { |
+ static_cast<int32_t>(0xf0000000), static_cast<int32_t>(0x00000001), |
+ static_cast<int32_t>(0xff000000), static_cast<int32_t>(0x0000f000), |
+ static_cast<int32_t>(0x0f000000), static_cast<int32_t>(0x991234ab), |
+ static_cast<int32_t>(0xb0ffff01), static_cast<int32_t>(0x00006fff), |
+ static_cast<int32_t>(0xffffffff)}; |
+ return std::vector<int32_t>(&kValues[0], &kValues[arraysize(kValues)]); |
+} |
+ |
+enum OverflowBranchType { |
+ kAddBranchOverflow, |
+ kSubBranchOverflow, |
+}; |
+ |
+struct OverflowRegisterCombination { |
+ Register dst; |
+ Register left; |
+ Register right; |
+ Register scratch; |
+}; |
+ |
+static const std::vector<enum OverflowBranchType> overflow_branch_type() { |
+ static const enum OverflowBranchType kValues[] = {kAddBranchOverflow, |
+ kSubBranchOverflow}; |
+ return std::vector<enum OverflowBranchType>(&kValues[0], |
+ &kValues[arraysize(kValues)]); |
+} |
+ |
+static const std::vector<struct OverflowRegisterCombination> |
+overflow_register_combination() { |
+ static const struct OverflowRegisterCombination kValues[] = { |
+ {t0, t1, t2, t3}, {t0, t0, t2, t3}, {t0, t1, t0, t3}, {t0, t1, t1, t3}}; |
+ return std::vector<struct OverflowRegisterCombination>( |
+ &kValues[0], &kValues[arraysize(kValues)]); |
+} |
+ |
+template <typename T> |
+static bool IsAddOverflow(T x, T y) { |
+ DCHECK(std::numeric_limits<T>::is_integer); |
+ T max = std::numeric_limits<T>::max(); |
+ T min = std::numeric_limits<T>::min(); |
+ |
+ return (x > 0 && y > (max - x)) || (x < 0 && y < (min - x)); |
+} |
+ |
+template <typename T> |
+static bool IsSubOverflow(T x, T y) { |
+ DCHECK(std::numeric_limits<T>::is_integer); |
+ T max = std::numeric_limits<T>::max(); |
+ T min = std::numeric_limits<T>::min(); |
+ |
+ return (y > 0 && x < (min + y)) || (y < 0 && x > (max + y)); |
+} |
+ |
+template <typename IN_TYPE, typename Func> |
+static bool runOverflow(IN_TYPE valLeft, IN_TYPE valRight, |
+ Func GenerateOverflowInstructions) { |
+ typedef int32_t (*F_CVT)(char* x0, int x1, int x2, int x3, int x4); |
+ |
+ Isolate* isolate = CcTest::i_isolate(); |
+ HandleScope scope(isolate); |
+ MacroAssembler assm(isolate, nullptr, 0, |
+ v8::internal::CodeObjectRequired::kYes); |
+ MacroAssembler* masm = &assm; |
+ |
+ GenerateOverflowInstructions(masm, valLeft, valRight); |
+ __ jr(ra); |
+ __ nop(); |
+ |
+ CodeDesc desc; |
+ assm.GetCode(&desc); |
+ Handle<Code> code = isolate->factory()->NewCode( |
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); |
+ |
+ F_CVT f = FUNCTION_CAST<F_CVT>(code->entry()); |
+ |
+ int32_t r = |
+ reinterpret_cast<int32_t>(CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0)); |
+ |
+ DCHECK(r == 0 || r == 1); |
+ return r; |
+} |
+ |
+TEST(BranchOverflowInt32BothLabels) { |
+ FOR_INT32_INPUTS(i, overflow_int32_test_values) { |
+ FOR_INT32_INPUTS(j, overflow_int32_test_values) { |
+ FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) { |
+ FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination, |
+ overflow_register_combination) { |
+ int32_t ii = *i; |
+ int32_t jj = *j; |
+ enum OverflowBranchType branchType = *br; |
+ struct OverflowRegisterCombination rc = *regComb; |
+ |
+ // If left and right register are same then left and right |
+ // test values must also be same, otherwise we skip the test |
+ if (rc.left.code() == rc.right.code()) { |
+ if (ii != jj) { |
+ continue; |
+ } |
+ } |
+ |
+ bool res1 = runOverflow<int32_t>( |
+ ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft, |
+ int32_t valRight) { |
+ Label overflow, no_overflow, end; |
+ __ li(rc.left, valLeft); |
+ __ li(rc.right, valRight); |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ __ AddBranchOvf(rc.dst, rc.left, rc.right, &overflow, |
+ &no_overflow, rc.scratch); |
+ break; |
+ case kSubBranchOverflow: |
+ __ SubBranchOvf(rc.dst, rc.left, rc.right, &overflow, |
+ &no_overflow, rc.scratch); |
+ break; |
+ } |
+ __ li(v0, 2); |
+ __ Branch(&end); |
+ __ bind(&overflow); |
+ __ li(v0, 1); |
+ __ Branch(&end); |
+ __ bind(&no_overflow); |
+ __ li(v0, 0); |
+ __ bind(&end); |
+ }); |
+ |
+ bool res2 = runOverflow<int32_t>( |
+ ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft, |
+ int32_t valRight) { |
+ Label overflow, no_overflow, end; |
+ __ li(rc.left, valLeft); |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ __ AddBranchOvf(rc.dst, rc.left, Operand(valRight), |
+ &overflow, &no_overflow, rc.scratch); |
+ break; |
+ case kSubBranchOverflow: |
+ __ SubBranchOvf(rc.dst, rc.left, Operand(valRight), |
+ &overflow, &no_overflow, rc.scratch); |
+ break; |
+ } |
+ __ li(v0, 2); |
+ __ Branch(&end); |
+ __ bind(&overflow); |
+ __ li(v0, 1); |
+ __ Branch(&end); |
+ __ bind(&no_overflow); |
+ __ li(v0, 0); |
+ __ bind(&end); |
+ }); |
+ |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1); |
+ CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res2); |
+ break; |
+ case kSubBranchOverflow: |
+ CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1); |
+ CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res2); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+TEST(BranchOverflowInt32LeftLabel) { |
+ FOR_INT32_INPUTS(i, overflow_int32_test_values) { |
+ FOR_INT32_INPUTS(j, overflow_int32_test_values) { |
+ FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) { |
+ FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination, |
+ overflow_register_combination) { |
+ int32_t ii = *i; |
+ int32_t jj = *j; |
+ enum OverflowBranchType branchType = *br; |
+ struct OverflowRegisterCombination rc = *regComb; |
+ |
+ // If left and right register are same then left and right |
+ // test values must also be same, otherwise we skip the test |
+ if (rc.left.code() == rc.right.code()) { |
+ if (ii != jj) { |
+ continue; |
+ } |
+ } |
+ |
+ bool res1 = runOverflow<int32_t>( |
+ ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft, |
+ int32_t valRight) { |
+ Label overflow, end; |
+ __ li(rc.left, valLeft); |
+ __ li(rc.right, valRight); |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ __ AddBranchOvf(rc.dst, rc.left, rc.right, &overflow, NULL, |
+ rc.scratch); |
+ break; |
+ case kSubBranchOverflow: |
+ __ SubBranchOvf(rc.dst, rc.left, rc.right, &overflow, NULL, |
+ rc.scratch); |
+ break; |
+ } |
+ __ li(v0, 0); |
+ __ Branch(&end); |
+ __ bind(&overflow); |
+ __ li(v0, 1); |
+ __ bind(&end); |
+ }); |
+ |
+ bool res2 = runOverflow<int32_t>( |
+ ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft, |
+ int32_t valRight) { |
+ Label overflow, end; |
+ __ li(rc.left, valLeft); |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ __ AddBranchOvf(rc.dst, rc.left, Operand(valRight), |
+ &overflow, NULL, rc.scratch); |
+ break; |
+ case kSubBranchOverflow: |
+ __ SubBranchOvf(rc.dst, rc.left, Operand(valRight), |
+ &overflow, NULL, rc.scratch); |
+ break; |
+ } |
+ __ li(v0, 0); |
+ __ Branch(&end); |
+ __ bind(&overflow); |
+ __ li(v0, 1); |
+ __ bind(&end); |
+ }); |
+ |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1); |
+ CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res2); |
+ break; |
+ case kSubBranchOverflow: |
+ CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1); |
+ CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res2); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+TEST(BranchOverflowInt32RightLabel) { |
+ FOR_INT32_INPUTS(i, overflow_int32_test_values) { |
+ FOR_INT32_INPUTS(j, overflow_int32_test_values) { |
+ FOR_ENUM_INPUTS(br, OverflowBranchType, overflow_branch_type) { |
+ FOR_STRUCT_INPUTS(regComb, OverflowRegisterCombination, |
+ overflow_register_combination) { |
+ int32_t ii = *i; |
+ int32_t jj = *j; |
+ enum OverflowBranchType branchType = *br; |
+ struct OverflowRegisterCombination rc = *regComb; |
+ |
+ // If left and right register are same then left and right |
+ // test values must also be same, otherwise we skip the test |
+ if (rc.left.code() == rc.right.code()) { |
+ if (ii != jj) { |
+ continue; |
+ } |
+ } |
+ |
+ bool res1 = runOverflow<int32_t>( |
+ ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft, |
+ int32_t valRight) { |
+ Label no_overflow, end; |
+ __ li(rc.left, valLeft); |
+ __ li(rc.right, valRight); |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ __ AddBranchOvf(rc.dst, rc.left, rc.right, NULL, |
+ &no_overflow, rc.scratch); |
+ break; |
+ case kSubBranchOverflow: |
+ __ SubBranchOvf(rc.dst, rc.left, rc.right, NULL, |
+ &no_overflow, rc.scratch); |
+ break; |
+ } |
+ __ li(v0, 1); |
+ __ Branch(&end); |
+ __ bind(&no_overflow); |
+ __ li(v0, 0); |
+ __ bind(&end); |
+ }); |
+ |
+ bool res2 = runOverflow<int32_t>( |
+ ii, jj, [branchType, rc](MacroAssembler* masm, int32_t valLeft, |
+ int32_t valRight) { |
+ Label no_overflow, end; |
+ __ li(rc.left, valLeft); |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ __ AddBranchOvf(rc.dst, rc.left, Operand(valRight), NULL, |
+ &no_overflow, rc.scratch); |
+ break; |
+ case kSubBranchOverflow: |
+ __ SubBranchOvf(rc.dst, rc.left, Operand(valRight), NULL, |
+ &no_overflow, rc.scratch); |
+ break; |
+ } |
+ __ li(v0, 1); |
+ __ Branch(&end); |
+ __ bind(&no_overflow); |
+ __ li(v0, 0); |
+ __ bind(&end); |
+ }); |
+ |
+ switch (branchType) { |
+ case kAddBranchOverflow: |
+ CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res1); |
+ CHECK_EQ(IsAddOverflow<int32_t>(ii, jj), res2); |
+ break; |
+ case kSubBranchOverflow: |
+ CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res1); |
+ CHECK_EQ(IsSubOverflow<int32_t>(ii, jj), res2); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
TEST(min_max_nan) { |
CcTest::InitializeVM(); |
Isolate* isolate = CcTest::i_isolate(); |