Chromium Code Reviews| 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..dbec889e39a5ce6914b075fdee2e58d3084f2739 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) |
|
balazs.kilvady
2016/04/05 17:25:20
Instead of the above macro-magic I would prefer a
|
| 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> |
| +bool run_Overflow(IN_TYPE valLeft, IN_TYPE valRight, |
| + Func GenerateOverflowInstructions) { |
|
balazs.kilvady
2016/04/05 17:25:20
Functionname should be run_overflow or RunOverflow
|
| + 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 static_cast<bool>(r); |
|
balazs.kilvady
2016/04/05 17:25:20
Could be simply 'return r;' or 'return r != 0;'
|
| +} |
| + |
| +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 = run_Overflow<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 = run_Overflow<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 = run_Overflow<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 = run_Overflow<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 = run_Overflow<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 = run_Overflow<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(); |