| // Copyright 2016, VIXL authors |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // * Neither the name of ARM Limited nor the names of its contributors may be |
| // used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include <stdlib.h> |
| |
| #include "test-runner.h" |
| |
| #ifdef VIXL_INCLUDE_TARGET_AARCH32 |
| #include "aarch32/macro-assembler-aarch32.h" |
| #endif |
| |
| #ifdef VIXL_INCLUDE_TARGET_AARCH64 |
| #include "aarch64/macro-assembler-aarch64.h" |
| #endif |
| |
| #define STRINGIFY(x) #x |
| |
| #define TEST_AARCH32(Name) \ |
| namespace aarch32 { \ |
| void Test_##Name##_AArch32_Impl(); \ |
| } \ |
| void Test_##Name##_AArch32() { aarch32::Test_##Name##_AArch32_Impl(); } \ |
| Test test_##Name##_AArch32(STRINGIFY(AARCH32_SCRATCH_##Name), \ |
| &Test_##Name##_AArch32); \ |
| void aarch32::Test_##Name##_AArch32_Impl() |
| |
| #define TEST_AARCH64(Name) \ |
| namespace aarch64 { \ |
| void Test_##Name##_AArch64_Impl(); \ |
| } \ |
| void Test_##Name##_AArch64() { aarch64::Test_##Name##_AArch64_Impl(); } \ |
| Test test_##Name##_AArch64(STRINGIFY(AARCH64_SCRATCH_##Name), \ |
| &Test_##Name##_AArch64); \ |
| void aarch64::Test_##Name##_AArch64_Impl() |
| |
| #define SETUP() MacroAssembler masm |
| #define TEARDOWN() |
| |
| #define __ masm. |
| |
| namespace vixl { |
| |
| // UseScratchRegisterScopes must be able to nest perfectly. That is, they may |
| // nest, but nested scopes must not outlive less-nested scopes. |
| template <typename MacroAssembler, typename UseScratchRegisterScope> |
| class PerfectNestingTestHelper { |
| public: |
| explicit PerfectNestingTestHelper(MacroAssembler* masm) : masm_(masm) { |
| uint16_t seed[3] = {4, 5, 6}; |
| seed48(seed); |
| } |
| void Run() { |
| UseScratchRegisterScope* top_scope = |
| masm_->GetCurrentScratchRegisterScope(); |
| int descendents = 0; |
| while (descendents < kMinimumDescendentScopeCount) descendents += Run(0); |
| VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == top_scope); |
| } |
| |
| private: |
| int Run(int depth) { |
| // As the depth increases, the probability of recursion decreases. |
| // At depth = kDepthLimit, we never recurse. |
| int max_children = static_cast<int>(std::abs(mrand48()) % kDepthLimit); |
| int children = std::max(0, max_children - depth); |
| int descendents = children; |
| while (children-- > 0) { |
| UseScratchRegisterScope scope(masm_); |
| VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == &scope); |
| descendents += Run(depth + 1); |
| VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == &scope); |
| } |
| return descendents; |
| } |
| |
| MacroAssembler* masm_; |
| static const int kDepthLimit = 12; |
| static const int kMinimumDescendentScopeCount = 10000; |
| }; |
| |
| #ifdef VIXL_INCLUDE_TARGET_AARCH32 |
| TEST_AARCH32(perfect_nesting) { |
| SETUP(); |
| PerfectNestingTestHelper<MacroAssembler, UseScratchRegisterScope>(&masm) |
| .Run(); |
| TEARDOWN(); |
| } |
| #endif // VIXL_INCLUDE_TARGET_AARCH32 |
| |
| #ifdef VIXL_INCLUDE_TARGET_AARCH64 |
| TEST_AARCH64(perfect_nesting) { |
| SETUP(); |
| PerfectNestingTestHelper<MacroAssembler, UseScratchRegisterScope>(&masm) |
| .Run(); |
| TEARDOWN(); |
| } |
| #endif // VIXL_INCLUDE_TARGET_AARCH64 |
| |
| |
| #ifdef VIXL_INCLUDE_TARGET_AARCH32 |
| TEST_AARCH32(v_registers) { |
| SETUP(); |
| { |
| UseScratchRegisterScope temps(&masm); |
| temps.Include(VRegisterList(q0, q1, q2, q3)); |
| |
| // This test assumes that low-numbered registers are allocated first. The |
| // implementation is allowed to use a different strategy; if it does, the |
| // test will need to be updated. |
| // TODO: Write more flexible (and thorough) tests. |
| |
| VIXL_CHECK(q0.Is(temps.AcquireQ())); |
| VIXL_CHECK(!temps.IsAvailable(q0)); |
| VIXL_CHECK(!temps.IsAvailable(d0)); |
| VIXL_CHECK(!temps.IsAvailable(d1)); |
| VIXL_CHECK(!temps.IsAvailable(s0)); |
| VIXL_CHECK(!temps.IsAvailable(s1)); |
| VIXL_CHECK(!temps.IsAvailable(s2)); |
| VIXL_CHECK(!temps.IsAvailable(s3)); |
| |
| VIXL_CHECK(d2.Is(temps.AcquireV(64))); |
| VIXL_CHECK(!temps.IsAvailable(q1)); |
| VIXL_CHECK(!temps.IsAvailable(d2)); |
| VIXL_CHECK(temps.IsAvailable(d3)); |
| VIXL_CHECK(!temps.IsAvailable(s4)); |
| VIXL_CHECK(!temps.IsAvailable(s5)); |
| VIXL_CHECK(temps.IsAvailable(s6)); |
| VIXL_CHECK(temps.IsAvailable(s7)); |
| |
| VIXL_CHECK(s6.Is(temps.AcquireS())); |
| VIXL_CHECK(!temps.IsAvailable(d3)); |
| VIXL_CHECK(!temps.IsAvailable(s6)); |
| VIXL_CHECK(temps.IsAvailable(s7)); |
| |
| VIXL_CHECK(q2.Is(temps.AcquireV(128))); |
| VIXL_CHECK(!temps.IsAvailable(q2)); |
| VIXL_CHECK(!temps.IsAvailable(d4)); |
| VIXL_CHECK(!temps.IsAvailable(d5)); |
| VIXL_CHECK(!temps.IsAvailable(s8)); |
| VIXL_CHECK(!temps.IsAvailable(s9)); |
| VIXL_CHECK(!temps.IsAvailable(s10)); |
| VIXL_CHECK(!temps.IsAvailable(s11)); |
| VIXL_CHECK(temps.IsAvailable(s7)); |
| |
| VIXL_CHECK(d6.Is(temps.AcquireD())); |
| VIXL_CHECK(!temps.IsAvailable(q3)); |
| VIXL_CHECK(!temps.IsAvailable(d6)); |
| VIXL_CHECK(temps.IsAvailable(d7)); |
| VIXL_CHECK(!temps.IsAvailable(s12)); |
| VIXL_CHECK(!temps.IsAvailable(s13)); |
| VIXL_CHECK(temps.IsAvailable(s14)); |
| VIXL_CHECK(temps.IsAvailable(s15)); |
| VIXL_CHECK(temps.IsAvailable(s7)); |
| |
| VIXL_CHECK(s7.Is(temps.AcquireS())); |
| } |
| TEARDOWN(); |
| } |
| #endif // VIXL_INCLUDE_TARGET_AARCH32 |
| |
| |
| #ifdef VIXL_INCLUDE_TARGET_AARCH32 |
| TEST_AARCH32(include_exclude) { |
| SETUP(); |
| { |
| UseScratchRegisterScope temps(&masm); |
| temps.Include(r0, r1, r2, r3); |
| temps.Include(s0, s1, d1, q1); |
| |
| VIXL_CHECK(temps.IsAvailable(r0)); |
| VIXL_CHECK(temps.IsAvailable(r1)); |
| VIXL_CHECK(temps.IsAvailable(r2)); |
| VIXL_CHECK(temps.IsAvailable(r3)); |
| |
| VIXL_CHECK(temps.IsAvailable(s0)); |
| |
| VIXL_CHECK(temps.IsAvailable(s1)); |
| |
| VIXL_CHECK(temps.IsAvailable(d1)); |
| VIXL_CHECK(temps.IsAvailable(s2)); |
| VIXL_CHECK(temps.IsAvailable(s3)); |
| |
| VIXL_CHECK(temps.IsAvailable(q1)); |
| VIXL_CHECK(temps.IsAvailable(d2)); |
| VIXL_CHECK(temps.IsAvailable(d3)); |
| VIXL_CHECK(temps.IsAvailable(s4)); |
| VIXL_CHECK(temps.IsAvailable(s5)); |
| VIXL_CHECK(temps.IsAvailable(s6)); |
| VIXL_CHECK(temps.IsAvailable(s7)); |
| |
| // Test local exclusion. |
| { |
| UseScratchRegisterScope local_temps(&masm); |
| local_temps.Exclude(r1, r2); |
| local_temps.Exclude(s1, q1); |
| |
| VIXL_CHECK(temps.IsAvailable(r0)); |
| VIXL_CHECK(!temps.IsAvailable(r1)); |
| VIXL_CHECK(!temps.IsAvailable(r2)); |
| VIXL_CHECK(temps.IsAvailable(r3)); |
| |
| VIXL_CHECK(temps.IsAvailable(s0)); |
| |
| VIXL_CHECK(!temps.IsAvailable(s1)); |
| |
| VIXL_CHECK(temps.IsAvailable(d1)); |
| VIXL_CHECK(temps.IsAvailable(s2)); |
| VIXL_CHECK(temps.IsAvailable(s3)); |
| |
| VIXL_CHECK(!temps.IsAvailable(q1)); |
| VIXL_CHECK(!temps.IsAvailable(d2)); |
| VIXL_CHECK(!temps.IsAvailable(d3)); |
| VIXL_CHECK(!temps.IsAvailable(s4)); |
| VIXL_CHECK(!temps.IsAvailable(s5)); |
| VIXL_CHECK(!temps.IsAvailable(s6)); |
| VIXL_CHECK(!temps.IsAvailable(s7)); |
| } |
| |
| // This time, exclude part of included registers, making sure the entire |
| // register gets excluded. |
| { |
| UseScratchRegisterScope local_temps(&masm); |
| local_temps.Exclude(s2, d3); |
| |
| VIXL_CHECK(temps.IsAvailable(r0)); |
| VIXL_CHECK(temps.IsAvailable(r1)); |
| VIXL_CHECK(temps.IsAvailable(r2)); |
| VIXL_CHECK(temps.IsAvailable(r3)); |
| |
| VIXL_CHECK(temps.IsAvailable(s0)); |
| |
| VIXL_CHECK(temps.IsAvailable(s1)); |
| |
| // Excluding s2 should exclude d1 but not s3. |
| VIXL_CHECK(!temps.IsAvailable(d1)); |
| VIXL_CHECK(!temps.IsAvailable(s2)); |
| VIXL_CHECK(temps.IsAvailable(s3)); |
| |
| // Excluding d3 should exclude q1, s7 and s6 but not d2, s5, s4. |
| VIXL_CHECK(!temps.IsAvailable(q1)); |
| VIXL_CHECK(temps.IsAvailable(d2)); |
| VIXL_CHECK(!temps.IsAvailable(d3)); |
| VIXL_CHECK(temps.IsAvailable(s4)); |
| VIXL_CHECK(temps.IsAvailable(s5)); |
| VIXL_CHECK(!temps.IsAvailable(s6)); |
| VIXL_CHECK(!temps.IsAvailable(s7)); |
| } |
| |
| // Make sure the initial state was restored. |
| |
| VIXL_CHECK(temps.IsAvailable(r0)); |
| VIXL_CHECK(temps.IsAvailable(r1)); |
| VIXL_CHECK(temps.IsAvailable(r2)); |
| VIXL_CHECK(temps.IsAvailable(r3)); |
| |
| VIXL_CHECK(temps.IsAvailable(s0)); |
| |
| VIXL_CHECK(temps.IsAvailable(s1)); |
| |
| VIXL_CHECK(temps.IsAvailable(d1)); |
| VIXL_CHECK(temps.IsAvailable(s2)); |
| VIXL_CHECK(temps.IsAvailable(s3)); |
| |
| VIXL_CHECK(temps.IsAvailable(q1)); |
| VIXL_CHECK(temps.IsAvailable(d2)); |
| VIXL_CHECK(temps.IsAvailable(d3)); |
| VIXL_CHECK(temps.IsAvailable(s4)); |
| VIXL_CHECK(temps.IsAvailable(s5)); |
| VIXL_CHECK(temps.IsAvailable(s6)); |
| VIXL_CHECK(temps.IsAvailable(s7)); |
| } |
| TEARDOWN(); |
| } |
| #endif // VIXL_INCLUDE_TARGET_AARCH32 |
| |
| } // namespace vixl |