mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-28 11:10:26 +00:00
1257 lines
36 KiB
C++
1257 lines
36 KiB
C++
/*
|
|
* Copyright (c) 2020, 2025, 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 "opto/chaitin.hpp"
|
|
#include "opto/opcodes.hpp"
|
|
#include "opto/regmask.hpp"
|
|
#include "unittest.hpp"
|
|
|
|
// Sanity tests for RegMask and RegMaskIterator. The file tests operations on
|
|
// combinations of different RegMask versions ("basic", i.e. only statically
|
|
// allocated and "extended", i.e. extended with dynamically allocated memory).
|
|
|
|
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_empty());
|
|
} else {
|
|
ASSERT_TRUE(rm.is_empty());
|
|
ASSERT_TRUE(!rm.is_infinite_stack());
|
|
}
|
|
|
|
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 rm.rm_size_bits()
|
|
RegMask rm;
|
|
rm.set_all();
|
|
ASSERT_TRUE(rm.size() == rm.rm_size_in_bits());
|
|
ASSERT_TRUE(!rm.is_empty());
|
|
// set_all sets infinite_stack
|
|
ASSERT_TRUE(rm.is_infinite_stack());
|
|
contains_expected_num_of_registers(rm, rm.rm_size_in_bits());
|
|
}
|
|
|
|
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_with) {
|
|
RegMask rm1;
|
|
rm1.insert(OptoReg::Name(1));
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(1)));
|
|
|
|
rm1.and_with(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
|
|
RegMask rm2;
|
|
rm1.and_with(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
}
|
|
|
|
TEST_VM(RegMask, or_with) {
|
|
RegMask rm1;
|
|
rm1.insert(OptoReg::Name(1));
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(1)));
|
|
|
|
rm1.or_with(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
|
|
RegMask rm2;
|
|
rm1.or_with(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 < (int)rm1.rm_size_in_bits(); i++) {
|
|
rm1.insert(i);
|
|
}
|
|
rm1.set_infinite_stack(true);
|
|
ASSERT_TRUE(rm1.is_infinite_stack());
|
|
rm2.subtract(rm1);
|
|
contains_expected_num_of_registers(rm1, rm1.rm_size_in_bits() - 17);
|
|
contains_expected_num_of_registers(rm2, 17);
|
|
}
|
|
|
|
TEST_VM(RegMask, subtract_inner) {
|
|
RegMask rm1;
|
|
RegMask rm2;
|
|
rm2.set_all();
|
|
for (int i = 17; i < (int)rm1.rm_size_in_bits(); i++) {
|
|
rm1.insert(i);
|
|
}
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm1, rm1.rm_size_in_bits() - 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 < (int)rm.rm_size_in_bits() - 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);
|
|
}
|
|
// infinite_stack does not count as a bound register
|
|
rm.set_infinite_stack(true);
|
|
ASSERT_FALSE(rm.is_bound1());
|
|
}
|
|
|
|
TEST_VM(RegMask, is_bound_pair) {
|
|
RegMask rm;
|
|
ASSERT_TRUE(rm.is_bound_pair());
|
|
for (int i = 0; i < (int)rm.rm_size_in_bits() - 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 infinite bit does not count as a bound pair
|
|
rm.clear();
|
|
rm.insert(rm.rm_size_in_bits() - 2);
|
|
rm.insert(rm.rm_size_in_bits() - 1);
|
|
rm.set_infinite_stack(true);
|
|
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 < (int)rm.rm_size_in_bits() - 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 infinite_stack does not count as a bound set
|
|
for (int j = rm.rm_size_in_bits() - size; j < (int)rm.rm_size_in_bits(); j++) {
|
|
rm.insert(j);
|
|
}
|
|
rm.set_infinite_stack(true);
|
|
ASSERT_FALSE(rm.is_bound_set(size));
|
|
rm.clear();
|
|
}
|
|
}
|
|
|
|
TEST_VM(RegMask, external_member) {
|
|
RegMask rm;
|
|
rm.set_infinite_stack(false);
|
|
ASSERT_FALSE(rm.member(OptoReg::Name(rm.rm_size_in_bits())));
|
|
rm.set_infinite_stack(true);
|
|
ASSERT_TRUE(rm.member(OptoReg::Name(rm.rm_size_in_bits())));
|
|
}
|
|
|
|
TEST_VM(RegMask, find_element) {
|
|
RegMask rm;
|
|
rm.insert(OptoReg::Name(44));
|
|
rm.insert(OptoReg::Name(30));
|
|
rm.insert(OptoReg::Name(54));
|
|
ASSERT_EQ(rm.find_first_elem(), OptoReg::Name(30));
|
|
ASSERT_EQ(rm.find_last_elem(), OptoReg::Name(54));
|
|
rm.set_infinite_stack(true);
|
|
ASSERT_EQ(rm.find_last_elem(), OptoReg::Name(54));
|
|
rm.clear();
|
|
ASSERT_EQ(rm.find_first_elem(), OptoReg::Bad);
|
|
ASSERT_EQ(rm.find_last_elem(), OptoReg::Bad);
|
|
}
|
|
|
|
TEST_VM(RegMask, find_first_set) {
|
|
RegMask rm;
|
|
LRG lrg;
|
|
lrg._is_scalable = 0;
|
|
lrg._is_vector = 0;
|
|
ASSERT_EQ(rm.find_first_set(lrg, 2), OptoReg::Bad);
|
|
rm.insert(OptoReg::Name(24));
|
|
rm.insert(OptoReg::Name(25));
|
|
rm.insert(OptoReg::Name(26));
|
|
rm.insert(OptoReg::Name(27));
|
|
rm.insert(OptoReg::Name(16));
|
|
rm.insert(OptoReg::Name(17));
|
|
rm.insert(OptoReg::Name(18));
|
|
rm.insert(OptoReg::Name(19));
|
|
ASSERT_EQ(rm.find_first_set(lrg, 4), OptoReg::Name(19));
|
|
}
|
|
|
|
TEST_VM(RegMask, alignment) {
|
|
RegMask rm;
|
|
rm.insert(OptoReg::Name(30));
|
|
rm.insert(OptoReg::Name(31));
|
|
ASSERT_TRUE(rm.is_aligned_sets(2));
|
|
rm.insert(OptoReg::Name(32));
|
|
rm.insert(OptoReg::Name(37));
|
|
rm.insert(OptoReg::Name(62));
|
|
rm.insert(OptoReg::Name(71));
|
|
rm.insert(OptoReg::Name(74));
|
|
rm.insert(OptoReg::Name(75));
|
|
ASSERT_FALSE(rm.is_aligned_pairs());
|
|
rm.clear_to_pairs();
|
|
ASSERT_TRUE(rm.is_aligned_sets(2));
|
|
ASSERT_TRUE(rm.is_aligned_pairs());
|
|
contains_expected_num_of_registers(rm, 4);
|
|
ASSERT_TRUE(rm.member(OptoReg::Name(30)));
|
|
ASSERT_TRUE(rm.member(OptoReg::Name(31)));
|
|
ASSERT_TRUE(rm.member(OptoReg::Name(74)));
|
|
ASSERT_TRUE(rm.member(OptoReg::Name(75)));
|
|
ASSERT_FALSE(rm.is_misaligned_pair());
|
|
rm.remove(OptoReg::Name(30));
|
|
rm.remove(OptoReg::Name(74));
|
|
ASSERT_TRUE(rm.is_misaligned_pair());
|
|
}
|
|
|
|
TEST_VM(RegMask, clear_to_sets) {
|
|
RegMask rm;
|
|
rm.insert(OptoReg::Name(3));
|
|
rm.insert(OptoReg::Name(20));
|
|
rm.insert(OptoReg::Name(21));
|
|
rm.insert(OptoReg::Name(22));
|
|
rm.insert(OptoReg::Name(23));
|
|
rm.insert(OptoReg::Name(25));
|
|
rm.insert(OptoReg::Name(26));
|
|
rm.insert(OptoReg::Name(27));
|
|
rm.insert(OptoReg::Name(40));
|
|
rm.insert(OptoReg::Name(42));
|
|
rm.insert(OptoReg::Name(43));
|
|
rm.insert(OptoReg::Name(44));
|
|
rm.insert(OptoReg::Name(45));
|
|
rm.clear_to_sets(2);
|
|
ASSERT_TRUE(rm.is_aligned_sets(2));
|
|
contains_expected_num_of_registers(rm, 10);
|
|
rm.clear_to_sets(4);
|
|
ASSERT_TRUE(rm.is_aligned_sets(4));
|
|
contains_expected_num_of_registers(rm, 4);
|
|
rm.clear_to_sets(8);
|
|
ASSERT_TRUE(rm.is_aligned_sets(8));
|
|
contains_expected_num_of_registers(rm, 0);
|
|
}
|
|
|
|
TEST_VM(RegMask, smear_to_sets) {
|
|
RegMask rm;
|
|
rm.insert(OptoReg::Name(3));
|
|
rm.smear_to_sets(2);
|
|
ASSERT_TRUE(rm.is_aligned_sets(2));
|
|
contains_expected_num_of_registers(rm, 2);
|
|
rm.smear_to_sets(4);
|
|
ASSERT_TRUE(rm.is_aligned_sets(4));
|
|
contains_expected_num_of_registers(rm, 4);
|
|
rm.smear_to_sets(8);
|
|
ASSERT_TRUE(rm.is_aligned_sets(8));
|
|
contains_expected_num_of_registers(rm, 8);
|
|
rm.smear_to_sets(16);
|
|
ASSERT_TRUE(rm.is_aligned_sets(16));
|
|
contains_expected_num_of_registers(rm, 16);
|
|
}
|
|
|
|
TEST_VM(RegMask, overlap) {
|
|
RegMask rm1;
|
|
RegMask rm2;
|
|
ASSERT_FALSE(rm1.overlap(rm2));
|
|
ASSERT_FALSE(rm2.overlap(rm1));
|
|
rm1.insert(OptoReg::Name(23));
|
|
rm1.insert(OptoReg::Name(2));
|
|
rm1.insert(OptoReg::Name(12));
|
|
rm2.insert(OptoReg::Name(1));
|
|
rm2.insert(OptoReg::Name(4));
|
|
ASSERT_FALSE(rm1.overlap(rm2));
|
|
ASSERT_FALSE(rm2.overlap(rm1));
|
|
rm1.insert(OptoReg::Name(4));
|
|
ASSERT_TRUE(rm1.overlap(rm2));
|
|
ASSERT_TRUE(rm2.overlap(rm1));
|
|
}
|
|
|
|
TEST_VM(RegMask, valid_reg) {
|
|
RegMask rm;
|
|
ASSERT_FALSE(rm.is_valid_reg(OptoReg::Name(42), 1));
|
|
rm.insert(OptoReg::Name(3));
|
|
rm.insert(OptoReg::Name(5));
|
|
rm.insert(OptoReg::Name(6));
|
|
rm.insert(OptoReg::Name(7));
|
|
ASSERT_FALSE(rm.is_valid_reg(OptoReg::Name(7), 4));
|
|
ASSERT_TRUE(rm.is_valid_reg(OptoReg::Name(7), 2));
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_insert_remove) {
|
|
RegMask rm;
|
|
OptoReg::Name reg1(rm.rm_size_in_bits() + 42);
|
|
OptoReg::Name reg2(rm.rm_size_in_bits() * 2 + 42);
|
|
rm.set_infinite_stack(true);
|
|
ASSERT_TRUE(rm.member(reg1));
|
|
rm.rollover();
|
|
rm.clear();
|
|
rm.insert(reg1);
|
|
ASSERT_TRUE(rm.member(reg1));
|
|
rm.remove(reg1);
|
|
ASSERT_FALSE(rm.member(reg1));
|
|
rm.set_infinite_stack(true);
|
|
rm.rollover();
|
|
rm.clear();
|
|
rm.insert(reg2);
|
|
ASSERT_FALSE(rm.member(reg1));
|
|
ASSERT_TRUE(rm.member(reg2));
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_find) {
|
|
RegMask rm;
|
|
OptoReg::Name reg1(rm.rm_size_in_bits() + 42);
|
|
OptoReg::Name reg2(rm.rm_size_in_bits() + 7);
|
|
rm.set_infinite_stack(true);
|
|
rm.rollover();
|
|
rm.clear();
|
|
ASSERT_EQ(rm.find_first_elem(), OptoReg::Bad);
|
|
ASSERT_EQ(rm.find_last_elem(), OptoReg::Bad);
|
|
rm.insert(reg1);
|
|
rm.insert(reg2);
|
|
ASSERT_EQ(rm.find_first_elem(), reg2);
|
|
ASSERT_EQ(rm.find_last_elem(), reg1);
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_find_first_set) {
|
|
LRG lrg;
|
|
lrg._is_scalable = 0;
|
|
lrg._is_vector = 0;
|
|
RegMask rm;
|
|
OptoReg::Name reg1(rm.rm_size_in_bits() + 24);
|
|
OptoReg::Name reg2(rm.rm_size_in_bits() + 25);
|
|
OptoReg::Name reg3(rm.rm_size_in_bits() + 26);
|
|
OptoReg::Name reg4(rm.rm_size_in_bits() + 27);
|
|
OptoReg::Name reg5(rm.rm_size_in_bits() + 16);
|
|
OptoReg::Name reg6(rm.rm_size_in_bits() + 17);
|
|
OptoReg::Name reg7(rm.rm_size_in_bits() + 18);
|
|
OptoReg::Name reg8(rm.rm_size_in_bits() + 19);
|
|
rm.set_infinite_stack(true);
|
|
rm.rollover();
|
|
rm.clear();
|
|
ASSERT_EQ(rm.find_first_set(lrg, 2), OptoReg::Bad);
|
|
rm.insert(reg1);
|
|
rm.insert(reg2);
|
|
rm.insert(reg3);
|
|
rm.insert(reg4);
|
|
rm.insert(reg5);
|
|
rm.insert(reg6);
|
|
rm.insert(reg7);
|
|
rm.insert(reg8);
|
|
ASSERT_EQ(rm.find_first_set(lrg, 4), reg8);
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_set_all_from) {
|
|
RegMask rm;
|
|
OptoReg::Name reg1(rm.rm_size_in_bits() + 42);
|
|
rm.set_infinite_stack(true);
|
|
rm.rollover();
|
|
rm.clear();
|
|
rm.set_all_from(reg1);
|
|
contains_expected_num_of_registers(rm, rm.rm_size_in_bits() - 42);
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_set_all_from_offset) {
|
|
RegMask rm;
|
|
rm.set_infinite_stack(true);
|
|
rm.rollover();
|
|
rm.clear();
|
|
rm.set_all_from_offset();
|
|
contains_expected_num_of_registers(rm, rm.rm_size_in_bits());
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_iterate) {
|
|
RegMask rm;
|
|
OptoReg::Name reg1(rm.rm_size_in_bits() + 2);
|
|
OptoReg::Name reg2(rm.rm_size_in_bits() + 6);
|
|
OptoReg::Name reg3(rm.rm_size_in_bits() + 17);
|
|
OptoReg::Name reg4(rm.rm_size_in_bits() + 43);
|
|
rm.set_infinite_stack(true);
|
|
rm.rollover();
|
|
rm.clear();
|
|
rm.insert(reg1);
|
|
rm.insert(reg2);
|
|
rm.insert(reg3);
|
|
rm.insert(reg4);
|
|
RegMaskIterator rmi(rm);
|
|
ASSERT_EQ(rmi.next(), reg1);
|
|
ASSERT_EQ(rmi.next(), reg2);
|
|
ASSERT_EQ(rmi.next(), reg3);
|
|
ASSERT_EQ(rmi.next(), reg4);
|
|
ASSERT_FALSE(rmi.has_next());
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_subtract_inner_disjoint) {
|
|
RegMask rm1;
|
|
RegMask rm2;
|
|
OptoReg::Name reg1(rm1.rm_size_in_bits() + 42);
|
|
rm1.set_infinite_stack(true);
|
|
rm1.rollover();
|
|
rm1.clear();
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
rm1.insert(reg1);
|
|
rm2.insert(42);
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 1);
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_subtract_inner_overlap) {
|
|
RegMask rm1;
|
|
RegMask rm2;
|
|
OptoReg::Name reg1(rm1.rm_size_in_bits() + 42);
|
|
rm1.set_infinite_stack(true);
|
|
rm1.rollover();
|
|
rm1.clear();
|
|
rm2.set_infinite_stack(true);
|
|
rm2.rollover();
|
|
rm2.clear();
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
rm1.insert(reg1);
|
|
rm2.insert(reg1);
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
rm1.insert(reg1);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
}
|
|
|
|
#ifdef ASSERT
|
|
|
|
TEST_VM_ASSERT_MSG(RegMask, unexpected_clone, ".*clone sanity check") {
|
|
RegMask rm1;
|
|
RegMask rm2;
|
|
// Copy contents of rm1 to rm2 inappropriately (no copy constructor)
|
|
memcpy((void*)&rm2, (void*)&rm1, sizeof(RegMask));
|
|
rm2.member(0); // Safeguard in RegMask must catch this.
|
|
}
|
|
|
|
TEST_VM_ASSERT_MSG(RegMask, unexpected_growth, ".*unexpected register mask growth") {
|
|
RegMask rm;
|
|
// Add clearly out of range OptoReg::Name
|
|
rm.insert(std::numeric_limits<OptoReg::Name>::max());
|
|
}
|
|
|
|
TEST_VM_ASSERT_MSG(RegMask, not_growable, ".*register mask not growable") {
|
|
RegMask rm;
|
|
// Add a bit just outside the mask, without having specified an arena for
|
|
// extension.
|
|
rm.insert(rm.rm_size_in_bits());
|
|
}
|
|
|
|
TEST_VM_ASSERT_MSG(RegMask, offset_mismatch, ".*offset mismatch") {
|
|
RegMask rm1;
|
|
RegMask rm2;
|
|
rm1.set_infinite_stack(true);
|
|
rm1.rollover();
|
|
// Cannot assign with different offsets
|
|
rm2.assignFrom(rm1);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef PRODUCT
|
|
|
|
Arena* arena() {
|
|
return Thread::current()->resource_area();
|
|
}
|
|
|
|
static void is_basic(const RegMask& rm) {
|
|
ASSERT_EQ(rm.rm_size_in_words(), RegMask::gtest_basic_rm_size_in_words());
|
|
}
|
|
|
|
static void is_extended(const RegMask& rm) {
|
|
ASSERT_TRUE(rm.rm_size_in_words() > RegMask::gtest_basic_rm_size_in_words());
|
|
}
|
|
|
|
static int first_extended() {
|
|
return RegMask::gtest_basic_rm_size_in_words() * BitsPerWord;
|
|
}
|
|
|
|
static void extend(RegMask& rm, unsigned int n = 4) {
|
|
// Extend the given RegMask with at least n dynamically-allocated words.
|
|
rm.insert(OptoReg::Name(first_extended() + (BitsPerWord * n) - 1));
|
|
rm.clear();
|
|
ASSERT_TRUE(rm.rm_size_in_words() >= RegMask::gtest_basic_rm_size_in_words() + n);
|
|
}
|
|
|
|
TEST_VM(RegMask, static_by_default) {
|
|
// Check that a freshly created RegMask does not allocate dynamic memory.
|
|
RegMask rm;
|
|
is_basic(rm);
|
|
}
|
|
|
|
TEST_VM(RegMask, iteration_extended) {
|
|
RegMask rm(arena());
|
|
rm.insert(30);
|
|
rm.insert(31);
|
|
rm.insert(33);
|
|
rm.insert(62);
|
|
rm.insert(first_extended());
|
|
rm.insert(first_extended() + 42);
|
|
rm.insert(first_extended() + 55);
|
|
rm.insert(first_extended() + 456);
|
|
|
|
RegMaskIterator rmi(rm);
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(30));
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(31));
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(33));
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(62));
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(first_extended()));
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(first_extended() + 42));
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(first_extended() + 55));
|
|
ASSERT_TRUE(rmi.next() == OptoReg::Name(first_extended() + 456));
|
|
ASSERT_FALSE(rmi.has_next());
|
|
}
|
|
|
|
TEST_VM(RegMask, set_all_extended) {
|
|
// Check that set_all doesn't add bits outside of rm.rm_size_bits() on
|
|
// extended RegMasks.
|
|
RegMask rm(arena());
|
|
extend(rm);
|
|
rm.set_all();
|
|
ASSERT_EQ(rm.size(), rm.rm_size_in_bits());
|
|
ASSERT_TRUE(!rm.is_empty());
|
|
// set_all sets infinite_stack bit
|
|
ASSERT_TRUE(rm.is_infinite_stack());
|
|
contains_expected_num_of_registers(rm, rm.rm_size_in_bits());
|
|
}
|
|
|
|
TEST_VM(RegMask, set_all_from_extended) {
|
|
RegMask rm(arena());
|
|
extend(rm);
|
|
rm.set_all_from(OptoReg::Name(42));
|
|
contains_expected_num_of_registers(rm, rm.rm_size_in_bits() - 42);
|
|
}
|
|
|
|
TEST_VM(RegMask, set_all_from_extended_grow) {
|
|
RegMask rm(arena());
|
|
rm.set_all_from(first_extended() + OptoReg::Name(42));
|
|
is_extended(rm);
|
|
contains_expected_num_of_registers(rm, rm.rm_size_in_bits() - first_extended() - 42);
|
|
}
|
|
|
|
TEST_VM(RegMask, clear_extended) {
|
|
// Check that clear doesn't leave any stray bits on extended RegMasks.
|
|
RegMask rm(arena());
|
|
rm.insert(first_extended());
|
|
is_extended(rm);
|
|
rm.set_all();
|
|
rm.clear();
|
|
contains_expected_num_of_registers(rm, 0);
|
|
}
|
|
|
|
TEST_VM(RegMask, and_with_extended_basic) {
|
|
RegMask rm1(arena());
|
|
rm1.insert(OptoReg::Name(first_extended()));
|
|
is_extended(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(first_extended())));
|
|
|
|
rm1.and_with(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
|
|
RegMask rm2;
|
|
is_basic(rm2);
|
|
rm1.and_with(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
}
|
|
|
|
TEST_VM(RegMask, and_with_extended_extended) {
|
|
RegMask rm1(arena());
|
|
rm1.insert(OptoReg::Name(first_extended()));
|
|
is_extended(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(first_extended())));
|
|
|
|
rm1.and_with(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
|
|
RegMask rm2(arena());
|
|
extend(rm2);
|
|
rm1.and_with(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
}
|
|
|
|
TEST_VM(RegMask, or_with_extended_basic) {
|
|
RegMask rm1(arena());
|
|
rm1.insert(OptoReg::Name(first_extended()));
|
|
is_extended(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(first_extended())));
|
|
|
|
rm1.or_with(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
|
|
RegMask rm2;
|
|
is_basic(rm2);
|
|
rm1.or_with(rm2);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
}
|
|
|
|
TEST_VM(RegMask, or_with_extended_extended) {
|
|
RegMask rm1(arena());
|
|
rm1.insert(OptoReg::Name(first_extended()));
|
|
is_extended(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(first_extended())));
|
|
|
|
rm1.or_with(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
|
|
RegMask rm2(arena());
|
|
extend(rm2);
|
|
rm1.or_with(rm2);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
}
|
|
|
|
TEST_VM(RegMask, subtract_extended) {
|
|
RegMask rm1(arena());
|
|
extend(rm1);
|
|
RegMask rm2(arena());
|
|
extend(rm2);
|
|
|
|
rm2.set_all();
|
|
ASSERT_TRUE(rm2.is_infinite_stack());
|
|
for (int i = first_extended() + 17; i < (int)rm1.rm_size_in_bits(); i++) {
|
|
rm1.insert(i);
|
|
}
|
|
rm1.set_infinite_stack(true);
|
|
ASSERT_TRUE(rm1.is_infinite_stack());
|
|
rm2.subtract(rm1);
|
|
contains_expected_num_of_registers(rm1, rm1.rm_size_in_bits() - first_extended() - 17);
|
|
contains_expected_num_of_registers(rm2, first_extended() + 17);
|
|
}
|
|
|
|
TEST_VM(RegMask, external_member_extended) {
|
|
RegMask rm(arena());
|
|
extend(rm);
|
|
rm.set_infinite_stack(false);
|
|
ASSERT_FALSE(rm.member(OptoReg::Name(rm.rm_size_in_bits())));
|
|
rm.set_infinite_stack(true);
|
|
ASSERT_TRUE(rm.member(OptoReg::Name(rm.rm_size_in_bits())));
|
|
}
|
|
|
|
TEST_VM(RegMask, overlap_extended) {
|
|
RegMask rm1(arena());
|
|
extend(rm1);
|
|
RegMask rm2(arena());
|
|
extend(rm2);
|
|
ASSERT_FALSE(rm1.overlap(rm2));
|
|
ASSERT_FALSE(rm2.overlap(rm1));
|
|
rm1.insert(OptoReg::Name(23));
|
|
rm1.insert(OptoReg::Name(2));
|
|
rm1.insert(OptoReg::Name(first_extended() + 12));
|
|
rm2.insert(OptoReg::Name(1));
|
|
rm2.insert(OptoReg::Name(first_extended() + 4));
|
|
ASSERT_FALSE(rm1.overlap(rm2));
|
|
ASSERT_FALSE(rm2.overlap(rm1));
|
|
rm1.insert(OptoReg::Name(first_extended() + 4));
|
|
ASSERT_TRUE(rm1.overlap(rm2));
|
|
ASSERT_TRUE(rm2.overlap(rm1));
|
|
}
|
|
|
|
TEST_VM(RegMask, up_extended) {
|
|
RegMask rm(arena());
|
|
extend(rm);
|
|
ASSERT_TRUE(rm.is_UP());
|
|
rm.insert(OptoReg::Name(1));
|
|
ASSERT_TRUE(rm.is_UP());
|
|
rm.insert(OptoReg::Name(first_extended()));
|
|
ASSERT_FALSE(rm.is_UP());
|
|
rm.clear();
|
|
rm.set_infinite_stack(true);
|
|
ASSERT_FALSE(rm.is_UP());
|
|
}
|
|
|
|
TEST_VM(RegMask, subtract_inner_basic_extended) {
|
|
RegMask rm1;
|
|
RegMask rm2(arena());
|
|
rm1.insert(OptoReg::Name(1));
|
|
rm1.insert(OptoReg::Name(42));
|
|
is_basic(rm1);
|
|
rm2.insert(OptoReg::Name(1));
|
|
rm2.insert(OptoReg::Name(first_extended() + 20));
|
|
is_extended(rm2);
|
|
rm1.subtract_inner(rm2);
|
|
is_basic(rm1);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(42)));
|
|
}
|
|
|
|
TEST_VM(RegMask, subtract_inner_extended_basic) {
|
|
RegMask rm1(arena());
|
|
RegMask rm2;
|
|
rm1.insert(OptoReg::Name(1));
|
|
rm1.insert(OptoReg::Name(42));
|
|
rm1.insert(OptoReg::Name(first_extended() + 20));
|
|
is_extended(rm1);
|
|
rm2.insert(OptoReg::Name(1));
|
|
is_basic(rm2);
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 2);
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(42)));
|
|
ASSERT_TRUE(rm1.member(OptoReg::Name(first_extended() + 20)));
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_extended) {
|
|
RegMask rm(arena());
|
|
extend(rm);
|
|
is_extended(rm);
|
|
OptoReg::Name reg1(rm.rm_size_in_bits() + 42);
|
|
rm.set_infinite_stack(true);
|
|
rm.rollover();
|
|
rm.insert(reg1);
|
|
ASSERT_TRUE(rm.member(reg1));
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_subtract_inner_disjoint_extended) {
|
|
RegMask rm1(arena());
|
|
RegMask rm2;
|
|
extend(rm1);
|
|
OptoReg::Name reg1(rm1.rm_size_in_bits() + 42);
|
|
rm1.set_infinite_stack(true);
|
|
rm1.rollover();
|
|
rm1.clear();
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
rm1.insert(reg1);
|
|
rm2.insert(42);
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 1);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 1);
|
|
}
|
|
|
|
TEST_VM(RegMask, rollover_and_subtract_inner_overlap_extended) {
|
|
RegMask rm1(arena());
|
|
RegMask rm2;
|
|
OptoReg::Name reg1(rm1.rm_size_in_bits() + 42);
|
|
extend(rm1);
|
|
rm2.set_infinite_stack(true);
|
|
rm2.rollover();
|
|
rm2.clear();
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
rm1.insert(reg1);
|
|
rm2.insert(reg1);
|
|
rm1.subtract_inner(rm2);
|
|
contains_expected_num_of_registers(rm1, 0);
|
|
rm1.insert(reg1);
|
|
rm2.subtract_inner(rm1);
|
|
contains_expected_num_of_registers(rm2, 0);
|
|
}
|
|
|
|
const uint iterations = 50000;
|
|
|
|
static uint r;
|
|
static uint next_random() {
|
|
r = os::next_random(r);
|
|
return r;
|
|
}
|
|
static void init_random() {
|
|
if (StressSeed == 0) {
|
|
r = static_cast<uint>(Ticks::now().nanoseconds());
|
|
tty->print_cr("seed: %u", r);
|
|
} else {
|
|
r = StressSeed;
|
|
}
|
|
}
|
|
|
|
static void print(const char* name, const RegMask& mask) {
|
|
tty->print("%s: ", name);
|
|
mask.print();
|
|
tty->print_cr(", size: %u, offset: %u, infinite_stack: %u", mask.rm_size_in_bits(),
|
|
mask.offset_bits(), mask.is_infinite_stack());
|
|
}
|
|
|
|
static void assert_equivalent(const RegMask& mask,
|
|
const ResourceBitMap& mask_ref,
|
|
bool infinite_stack_ref) {
|
|
ASSERT_EQ(mask_ref.count_one_bits(), mask.size());
|
|
RegMaskIterator it(mask);
|
|
OptoReg::Name reg = OptoReg::Bad;
|
|
while (it.has_next()) {
|
|
reg = it.next();
|
|
ASSERT_TRUE(OptoReg::is_valid(reg));
|
|
ASSERT_TRUE(mask_ref.at(reg));
|
|
}
|
|
ASSERT_EQ(infinite_stack_ref, mask.is_infinite_stack());
|
|
}
|
|
|
|
static void populate_auxiliary_sets(RegMask& mask_aux,
|
|
ResourceBitMap& mask_aux_ref,
|
|
uint reg_capacity, uint offset,
|
|
bool random_offset) {
|
|
mask_aux.clear();
|
|
mask_aux_ref.clear();
|
|
if (random_offset) {
|
|
uint offset_in_words = offset / BitsPerWord;
|
|
uint capacity_in_words = reg_capacity / BitsPerWord;
|
|
uint new_offset_in_words;
|
|
uint offset_target = next_random() % 3;
|
|
switch (offset_target) {
|
|
case 0: // before
|
|
if (offset_in_words == 0) {
|
|
new_offset_in_words = 0;
|
|
} else {
|
|
new_offset_in_words = next_random() % offset_in_words;
|
|
}
|
|
break;
|
|
case 1: // within
|
|
new_offset_in_words =
|
|
(next_random() % capacity_in_words) + offset_in_words;
|
|
break;
|
|
case 2: // after
|
|
new_offset_in_words = offset_in_words + capacity_in_words +
|
|
(next_random() % (capacity_in_words));
|
|
break;
|
|
default:
|
|
FAIL();
|
|
}
|
|
offset = new_offset_in_words * BitsPerWord;
|
|
if (offset + RegMask::gtest_rm_size_in_bits_max() > mask_aux_ref.size()) {
|
|
// Ensure that there is space in the reference mask.
|
|
offset = 0;
|
|
}
|
|
}
|
|
mask_aux.gtest_set_offset(offset / BitsPerWord);
|
|
assert_equivalent(mask_aux, mask_aux_ref, false);
|
|
uint max_size;
|
|
uint size_target = next_random() % 3;
|
|
switch (size_target) {
|
|
case 0: // smaller
|
|
max_size = reg_capacity / 2;
|
|
break;
|
|
case 1: // equal
|
|
max_size = reg_capacity;
|
|
break;
|
|
case 2: // larger (if possible)
|
|
max_size = RegMask::gtest_rm_size_in_bits_max();
|
|
break;
|
|
default:
|
|
FAIL();
|
|
}
|
|
uint regs;
|
|
uint regs_target = next_random() % 3;
|
|
switch (regs_target) {
|
|
case 0: // sparse
|
|
regs = next_random() % 8;
|
|
break;
|
|
case 1: // medium
|
|
regs = next_random() % (max_size / 8);
|
|
break;
|
|
case 2: // dense
|
|
regs = next_random() % max_size;
|
|
break;
|
|
default:
|
|
FAIL();
|
|
}
|
|
for (uint i = 0; i < regs; i++) {
|
|
uint reg = (next_random() % max_size) + offset;
|
|
mask_aux.insert(reg);
|
|
mask_aux_ref.set_bit(reg);
|
|
}
|
|
mask_aux.set_infinite_stack(next_random() % 2);
|
|
assert_equivalent(mask_aux, mask_aux_ref, mask_aux.is_infinite_stack());
|
|
|
|
if (Verbose) {
|
|
print("mask_aux", mask_aux);
|
|
}
|
|
}
|
|
|
|
static void stack_extend_ref_masks(ResourceBitMap& mask1, bool infinite_stack1,
|
|
uint size_bits1, uint offset1,
|
|
ResourceBitMap& mask2, bool infinite_stack2,
|
|
uint size_bits2, uint offset2) {
|
|
uint size_bits_after = MAX2(size_bits1, size_bits2);
|
|
if (infinite_stack1) {
|
|
mask1.set_range(size_bits1 + offset1, size_bits_after + offset1);
|
|
}
|
|
if (infinite_stack2) {
|
|
mask2.set_range(size_bits2 + offset2, size_bits_after + offset2);
|
|
}
|
|
}
|
|
|
|
TEST_VM(RegMask, random) {
|
|
ResourceMark rm;
|
|
RegMask mask(arena());
|
|
ResourceBitMap mask_ref(std::numeric_limits<short>::max() + 1);
|
|
bool infinite_stack_ref = false;
|
|
uint offset_ref = 0;
|
|
init_random();
|
|
|
|
for (uint i = 0; i < iterations; i++) {
|
|
if (Verbose) {
|
|
print("mask ", mask);
|
|
tty->print("%u. ", i);
|
|
}
|
|
uint action = next_random() % 13;
|
|
uint reg;
|
|
uint size_bits_before = mask.rm_size_in_bits();
|
|
// This copy is used for stack-extension in overlap.
|
|
ResourceBitMap mask_ref_copy(std::numeric_limits<short>::max() + 1);
|
|
mask_ref_copy.clear();
|
|
mask_ref.iterate([&](BitMap::idx_t index) {
|
|
mask_ref_copy.set_bit(index);
|
|
return true;
|
|
});
|
|
ResourceBitMap mask_aux_ref(std::numeric_limits<short>::max() + 1);
|
|
RegMask mask_aux(arena());
|
|
switch (action) {
|
|
case 0:
|
|
reg = (next_random() % RegMask::gtest_rm_size_in_bits_max()) + offset_ref;
|
|
if (Verbose) {
|
|
tty->print_cr("action: Insert");
|
|
tty->print("value : ");
|
|
OptoReg::dump(reg);
|
|
tty->cr();
|
|
}
|
|
mask.insert(reg);
|
|
mask_ref.set_bit(reg);
|
|
if (mask.is_infinite_stack() && reg >= size_bits_before) {
|
|
// Stack-extend reference bitset.
|
|
mask_ref.set_range(size_bits_before + offset_ref,
|
|
mask.rm_size_in_bits() + offset_ref);
|
|
}
|
|
break;
|
|
case 1:
|
|
reg = (next_random() % size_bits_before) + offset_ref;
|
|
if (Verbose) {
|
|
tty->print_cr("action: Remove");
|
|
tty->print("value : ");
|
|
OptoReg::dump(reg);
|
|
tty->cr();
|
|
}
|
|
mask.remove(reg);
|
|
mask_ref.clear_bit(reg);
|
|
break;
|
|
case 2:
|
|
if (Verbose) {
|
|
tty->print_cr("action: Clear");
|
|
}
|
|
mask.clear();
|
|
mask_ref.clear();
|
|
infinite_stack_ref = false;
|
|
break;
|
|
case 3:
|
|
if (offset_ref > 0) {
|
|
// set_all expects a zero-offset.
|
|
break;
|
|
}
|
|
if (Verbose) {
|
|
tty->print_cr("action: set_all");
|
|
}
|
|
mask.set_all();
|
|
mask_ref.set_range(0, size_bits_before);
|
|
infinite_stack_ref = true;
|
|
break;
|
|
case 4:
|
|
if (Verbose) {
|
|
tty->print_cr("action: and_with");
|
|
}
|
|
populate_auxiliary_sets(mask_aux, mask_aux_ref, mask.rm_size_in_bits(),
|
|
offset_ref, /*random_offset*/ false);
|
|
mask.and_with(mask_aux);
|
|
stack_extend_ref_masks(mask_ref, infinite_stack_ref, size_bits_before,
|
|
offset_ref, mask_aux_ref, mask_aux.is_infinite_stack(),
|
|
mask_aux.rm_size_in_bits(), mask_aux.offset_bits());
|
|
mask_ref.set_intersection(mask_aux_ref);
|
|
infinite_stack_ref = infinite_stack_ref && mask_aux.is_infinite_stack();
|
|
break;
|
|
case 5:
|
|
if (Verbose) {
|
|
tty->print_cr("action: or_with");
|
|
}
|
|
populate_auxiliary_sets(mask_aux, mask_aux_ref, mask.rm_size_in_bits(),
|
|
offset_ref, /*random_offset*/ false);
|
|
mask.or_with(mask_aux);
|
|
stack_extend_ref_masks(mask_ref, infinite_stack_ref, size_bits_before,
|
|
offset_ref, mask_aux_ref, mask_aux.is_infinite_stack(),
|
|
mask_aux.rm_size_in_bits(), mask_aux.offset_bits());
|
|
mask_ref.set_union(mask_aux_ref);
|
|
infinite_stack_ref = infinite_stack_ref || mask_aux.is_infinite_stack();
|
|
break;
|
|
case 6:
|
|
if (Verbose) {
|
|
tty->print_cr("action: subtract");
|
|
}
|
|
populate_auxiliary_sets(mask_aux, mask_aux_ref, mask.rm_size_in_bits(),
|
|
offset_ref, /*random_offset*/ false);
|
|
mask.subtract(mask_aux);
|
|
stack_extend_ref_masks(mask_ref, infinite_stack_ref, size_bits_before,
|
|
offset_ref, mask_aux_ref, mask_aux.is_infinite_stack(),
|
|
mask_aux.rm_size_in_bits(), mask_aux.offset_bits());
|
|
mask_ref.set_difference(mask_aux_ref);
|
|
if (mask_aux.is_infinite_stack()) {
|
|
infinite_stack_ref = false;
|
|
}
|
|
break;
|
|
case 7:
|
|
if (Verbose) {
|
|
tty->print_cr("action: subtract_inner");
|
|
}
|
|
populate_auxiliary_sets(mask_aux, mask_aux_ref, mask.rm_size_in_bits(),
|
|
offset_ref, /*random_offset*/ true);
|
|
// subtract_inner expects an argument register mask with infinite_stack =
|
|
// false.
|
|
mask_aux.set_infinite_stack(false);
|
|
mask.subtract_inner(mask_aux);
|
|
// subtract_inner does not have "stack-extension semantics".
|
|
mask_ref.set_difference(mask_aux_ref);
|
|
break;
|
|
case 8:
|
|
if (Verbose) {
|
|
tty->print_cr("action: overlap");
|
|
}
|
|
populate_auxiliary_sets(mask_aux, mask_aux_ref, mask.rm_size_in_bits(),
|
|
offset_ref, /*random_offset*/ false);
|
|
// Stack-extend a copy of mask_ref to avoid mutating the original.
|
|
stack_extend_ref_masks(mask_ref_copy, infinite_stack_ref, size_bits_before,
|
|
offset_ref, mask_aux_ref, mask_aux.is_infinite_stack(),
|
|
mask_aux.rm_size_in_bits(), mask_aux.offset_bits());
|
|
ASSERT_EQ(mask_ref_copy.intersects(mask_aux_ref) ||
|
|
(infinite_stack_ref && mask_aux.is_infinite_stack()),
|
|
mask.overlap(mask_aux));
|
|
break;
|
|
case 9:
|
|
if (Verbose) {
|
|
tty->print_cr("action: rollover");
|
|
}
|
|
// rollover expects the mask to be cleared and with infinite_stack = true
|
|
mask.clear();
|
|
mask.set_infinite_stack(true);
|
|
mask_ref.clear();
|
|
infinite_stack_ref = true;
|
|
if (mask.rollover()) {
|
|
offset_ref += size_bits_before;
|
|
mask_ref.set_range(offset_ref, offset_ref + size_bits_before);
|
|
}
|
|
break;
|
|
case 10:
|
|
if (Verbose) {
|
|
tty->print_cr("action: reset");
|
|
}
|
|
mask.gtest_set_offset(0);
|
|
mask.clear();
|
|
mask_ref.clear();
|
|
infinite_stack_ref = false;
|
|
offset_ref = 0;
|
|
break;
|
|
case 11:
|
|
if (Verbose) {
|
|
tty->print_cr("action: set_all_from_offset");
|
|
}
|
|
mask.set_all_from_offset();
|
|
mask_ref.set_range(offset_ref, offset_ref + size_bits_before);
|
|
infinite_stack_ref = true;
|
|
break;
|
|
case 12:
|
|
reg = (next_random() % size_bits_before) + offset_ref;
|
|
if (Verbose) {
|
|
tty->print_cr("action: set_all_from");
|
|
tty->print("value : ");
|
|
OptoReg::dump(reg);
|
|
tty->cr();
|
|
}
|
|
mask.set_all_from(reg);
|
|
mask_ref.set_range(reg, offset_ref + size_bits_before);
|
|
infinite_stack_ref = true;
|
|
break;
|
|
default:
|
|
FAIL() << "Unimplemented action";
|
|
}
|
|
ASSERT_NO_FATAL_FAILURE(assert_equivalent(mask, mask_ref, infinite_stack_ref));
|
|
}
|
|
}
|
|
|
|
// Randomly sets register mask contents. Does not change register mask size.
|
|
static void randomize(RegMask& rm) {
|
|
rm.clear();
|
|
// Uniform distribution over number of registers.
|
|
uint regs = next_random() % (rm.rm_size_in_bits() + 1);
|
|
for (uint i = 0; i < regs; i++) {
|
|
uint reg = (next_random() % rm.rm_size_in_bits()) + rm.offset_bits();
|
|
rm.insert(reg);
|
|
}
|
|
rm.set_infinite_stack(next_random() % 2);
|
|
}
|
|
|
|
static uint grow_randomly(RegMask& rm, uint min_growth = 1,
|
|
uint max_growth = 3) {
|
|
// Grow between min_growth and max_growth times.
|
|
uint grow = min_growth + (max_growth > 0 ? next_random() % max_growth : 0);
|
|
for (uint i = 0; i < grow; ++i) {
|
|
uint reg = rm.rm_size_in_bits();
|
|
if (reg >= RegMask::gtest_rm_size_in_bits_max()) {
|
|
// Cannot grow more
|
|
break;
|
|
}
|
|
// Force grow
|
|
rm.insert(reg);
|
|
if (!rm.is_infinite_stack()) {
|
|
// Restore
|
|
rm.remove(reg);
|
|
}
|
|
}
|
|
// Return how many times we grew
|
|
return grow;
|
|
}
|
|
|
|
TEST_VM(RegMask, random_copy) {
|
|
init_random();
|
|
|
|
auto print_failure = [&](const RegMask& src, const RegMask& dst) {
|
|
tty->print_cr("Failure, src and dst not equal");
|
|
tty->print("src: ");
|
|
src.dump_hex();
|
|
tty->cr();
|
|
tty->print("dst: ");
|
|
dst.dump_hex();
|
|
tty->cr();
|
|
};
|
|
|
|
// Test copying a larger register mask
|
|
for (uint i = 0; i < iterations; i++) {
|
|
ResourceMark rm;
|
|
|
|
// Create source RegMask
|
|
RegMask src(arena());
|
|
|
|
// Grow source randomly
|
|
grow_randomly(src);
|
|
|
|
// Randomly initialize source
|
|
randomize(src);
|
|
|
|
// Copy construct source to destination
|
|
RegMask dst(src, arena());
|
|
|
|
// Check equality
|
|
bool passed = src.gtest_equals(dst);
|
|
if (Verbose && !passed) {
|
|
print_failure(src, dst);
|
|
}
|
|
ASSERT_TRUE(passed);
|
|
}
|
|
|
|
// Test copying a smaller register mask
|
|
for (uint i = 0; i < iterations; i++) {
|
|
ResourceMark rm;
|
|
|
|
// Create destination RegMask
|
|
RegMask dst(arena());
|
|
|
|
// Grow destination arbitrarily (1-3 times)
|
|
uint growth = grow_randomly(dst, 1, 3);
|
|
|
|
// Create source RegMask
|
|
RegMask src(arena());
|
|
|
|
// Grow source arbitrarily, but not as much as destination
|
|
grow_randomly(src, 0, growth - 1);
|
|
|
|
// Randomly initialize source
|
|
randomize(src);
|
|
|
|
// Set destination to source
|
|
dst.assignFrom(src);
|
|
|
|
// Check equality
|
|
bool passed = src.gtest_equals(dst);
|
|
if (Verbose && !passed) {
|
|
print_failure(src, dst);
|
|
}
|
|
ASSERT_TRUE(passed);
|
|
}
|
|
}
|
|
|
|
#endif // !PRODUCT
|