| /* |
| * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "precompiled.hpp" |
| #include "opto/opcodes.hpp" |
| #include "opto/regmask.hpp" |
| #include "unittest.hpp" |
| |
| // Sanity tests for RegMask and RegMaskIterator |
| |
| static void contains_expected_num_of_registers(const RegMask& rm, unsigned int expected) { |
| |
| ASSERT_TRUE(rm.Size() == expected); |
| if (expected > 0) { |
| ASSERT_TRUE(rm.is_NotEmpty()); |
| } else { |
| ASSERT_TRUE(!rm.is_NotEmpty()); |
| ASSERT_TRUE(!rm.is_AllStack()); |
| } |
| |
| RegMaskIterator rmi(rm); |
| unsigned int count = 0; |
| OptoReg::Name reg = OptoReg::Bad; |
| while (rmi.has_next()) { |
| reg = rmi.next(); |
| ASSERT_TRUE(OptoReg::is_valid(reg)); |
| count++; |
| } |
| ASSERT_EQ(OptoReg::Bad, rmi.next()); |
| ASSERT_TRUE(count == expected); |
| } |
| |
| TEST_VM(RegMask, empty) { |
| RegMask rm; |
| contains_expected_num_of_registers(rm, 0); |
| } |
| |
| TEST_VM(RegMask, iteration) { |
| RegMask rm; |
| rm.Insert(30); |
| rm.Insert(31); |
| rm.Insert(32); |
| rm.Insert(33); |
| rm.Insert(62); |
| rm.Insert(63); |
| rm.Insert(64); |
| rm.Insert(65); |
| |
| RegMaskIterator rmi(rm); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(30)); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(31)); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(32)); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(33)); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(62)); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(63)); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(64)); |
| ASSERT_TRUE(rmi.next() == OptoReg::Name(65)); |
| ASSERT_FALSE(rmi.has_next()); |
| } |
| |
| TEST_VM(RegMask, Set_ALL) { |
| // Check that Set_All doesn't add bits outside of CHUNK_SIZE |
| RegMask rm; |
| rm.Set_All(); |
| ASSERT_TRUE(rm.Size() == RegMask::CHUNK_SIZE); |
| ASSERT_TRUE(rm.is_NotEmpty()); |
| // Set_All sets AllStack bit |
| ASSERT_TRUE(rm.is_AllStack()); |
| contains_expected_num_of_registers(rm, RegMask::CHUNK_SIZE); |
| } |
| |
| TEST_VM(RegMask, Clear) { |
| // Check that Clear doesn't leave any stray bits |
| RegMask rm; |
| rm.Set_All(); |
| rm.Clear(); |
| contains_expected_num_of_registers(rm, 0); |
| } |
| |
| TEST_VM(RegMask, AND) { |
| RegMask rm1; |
| rm1.Insert(OptoReg::Name(1)); |
| contains_expected_num_of_registers(rm1, 1); |
| ASSERT_TRUE(rm1.Member(OptoReg::Name(1))); |
| |
| rm1.AND(rm1); |
| contains_expected_num_of_registers(rm1, 1); |
| |
| RegMask rm2; |
| rm1.AND(rm2); |
| contains_expected_num_of_registers(rm1, 0); |
| contains_expected_num_of_registers(rm2, 0); |
| } |
| |
| TEST_VM(RegMask, OR) { |
| RegMask rm1; |
| rm1.Insert(OptoReg::Name(1)); |
| contains_expected_num_of_registers(rm1, 1); |
| ASSERT_TRUE(rm1.Member(OptoReg::Name(1))); |
| |
| rm1.OR(rm1); |
| contains_expected_num_of_registers(rm1, 1); |
| |
| RegMask rm2; |
| rm1.OR(rm2); |
| contains_expected_num_of_registers(rm1, 1); |
| contains_expected_num_of_registers(rm2, 0); |
| } |
| |
| TEST_VM(RegMask, SUBTRACT) { |
| RegMask rm1; |
| RegMask rm2; |
| |
| rm2.Set_All(); |
| for (int i = 17; i < RegMask::CHUNK_SIZE; i++) { |
| rm1.Insert(i); |
| } |
| ASSERT_TRUE(rm1.is_AllStack()); |
| rm2.SUBTRACT(rm1); |
| contains_expected_num_of_registers(rm1, RegMask::CHUNK_SIZE - 17); |
| contains_expected_num_of_registers(rm2, 17); |
| } |
| |
| TEST_VM(RegMask, is_bound1) { |
| RegMask rm; |
| ASSERT_FALSE(rm.is_bound1()); |
| for (int i = 0; i < RegMask::CHUNK_SIZE - 1; i++) { |
| rm.Insert(i); |
| ASSERT_TRUE(rm.is_bound1()) << "Index " << i; |
| ASSERT_TRUE(rm.is_bound(Op_RegI)) << "Index " << i; |
| contains_expected_num_of_registers(rm, 1); |
| rm.Remove(i); |
| } |
| // AllStack bit does not count as a bound register |
| rm.set_AllStack(); |
| ASSERT_FALSE(rm.is_bound1()); |
| } |
| |
| TEST_VM(RegMask, is_bound_pair) { |
| RegMask rm; |
| ASSERT_TRUE(rm.is_bound_pair()); |
| for (int i = 0; i < RegMask::CHUNK_SIZE - 2; i++) { |
| rm.Insert(i); |
| rm.Insert(i + 1); |
| ASSERT_TRUE(rm.is_bound_pair()) << "Index " << i; |
| ASSERT_TRUE(rm.is_bound_set(2)) << "Index " << i; |
| ASSERT_TRUE(rm.is_bound(Op_RegI)) << "Index " << i; |
| contains_expected_num_of_registers(rm, 2); |
| rm.Clear(); |
| } |
| // A pair with the AllStack bit does not count as a bound pair |
| rm.Clear(); |
| rm.Insert(RegMask::CHUNK_SIZE - 2); |
| rm.Insert(RegMask::CHUNK_SIZE - 1); |
| ASSERT_FALSE(rm.is_bound_pair()); |
| } |
| |
| TEST_VM(RegMask, is_bound_set) { |
| RegMask rm; |
| for (int size = 1; size <= 16; size++) { |
| ASSERT_TRUE(rm.is_bound_set(size)); |
| for (int i = 0; i < RegMask::CHUNK_SIZE - size; i++) { |
| for (int j = i; j < i + size; j++) { |
| rm.Insert(j); |
| } |
| ASSERT_TRUE(rm.is_bound_set(size)) << "Size " << size << " Index " << i; |
| contains_expected_num_of_registers(rm, size); |
| rm.Clear(); |
| } |
| // A set with the AllStack bit does not count as a bound set |
| for (int j = RegMask::CHUNK_SIZE - size; j < RegMask::CHUNK_SIZE; j++) { |
| rm.Insert(j); |
| } |
| ASSERT_FALSE(rm.is_bound_set(size)); |
| rm.Clear(); |
| } |
| } |