8347405: MergeStores with reverse bytes order value

Co-authored-by: Richard Reingruber <rrich@openjdk.org>
Reviewed-by: epeter, thartmann
This commit is contained in:
Kuai Wei 2025-03-11 02:07:19 +00:00 committed by Shaojin Wen
parent f984c2b32d
commit 5928209280
3 changed files with 212 additions and 84 deletions

View File

@ -2774,12 +2774,33 @@ class MergePrimitiveStores : public StackObj {
private:
PhaseGVN* const _phase;
StoreNode* const _store;
// State machine with initial state Unknown
// Allowed transitions:
// Unknown -> Const
// Unknown -> Platform
// Unknown -> Reverse
// Unknown -> NotAdjacent
// Const -> Const
// Const -> NotAdjacent
// Platform -> Platform
// Platform -> NotAdjacent
// Reverse -> Reverse
// Reverse -> NotAdjacent
// NotAdjacent -> NotAdjacent
enum ValueOrder : uint8_t {
Unknown, // Initial state
Const, // Input values are const
Platform, // Platform order
Reverse, // Reverse platform order
NotAdjacent // Not adjacent
};
ValueOrder _value_order;
NOT_PRODUCT( const CHeapBitMap &_trace_tags; )
public:
MergePrimitiveStores(PhaseGVN* phase, StoreNode* store) :
_phase(phase), _store(store)
_phase(phase), _store(store), _value_order(ValueOrder::Unknown)
NOT_PRODUCT( COMMA _trace_tags(Compile::current()->directive()->trace_merge_stores_tags()) )
{}
@ -2789,7 +2810,7 @@ private:
bool is_compatible_store(const StoreNode* other_store) const;
bool is_adjacent_pair(const StoreNode* use_store, const StoreNode* def_store) const;
bool is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const;
static bool is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out);
static bool is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out, PhaseGVN* phase);
enum CFGStatus { SuccessNoRangeCheck, SuccessWithRangeCheck, Failure };
static CFGStatus cfg_status_for_pair(const StoreNode* use_store, const StoreNode* def_store);
@ -2825,6 +2846,7 @@ private:
#endif
};
enum ValueOrder find_adjacent_input_value_order(const Node* n1, const Node* n2, const int memory_size) const;
Status find_adjacent_use_store(const StoreNode* def_store) const;
Status find_adjacent_def_store(const StoreNode* use_store) const;
Status find_use_store(const StoreNode* def_store) const;
@ -2886,10 +2908,17 @@ StoreNode* MergePrimitiveStores::run() {
// Check if we can merge with at least one def, so that we have at least 2 stores to merge.
Status status_def = find_adjacent_def_store(_store);
NOT_PRODUCT( if (is_trace_basic()) { tty->print("[TraceMergeStores] expect def: "); status_def.print_on(tty); })
if (status_def.found_store() == nullptr) {
Node* def_store = status_def.found_store();
if (def_store == nullptr) {
return nullptr;
}
// Initialize value order
_value_order = find_adjacent_input_value_order(def_store->in(MemNode::ValueIn),
_store->in(MemNode::ValueIn),
_store->memory_size());
assert(_value_order != ValueOrder::NotAdjacent && _value_order != ValueOrder::Unknown, "Order should be checked");
ResourceMark rm;
Node_List merge_list;
collect_merge_list(merge_list);
@ -2936,49 +2965,75 @@ bool MergePrimitiveStores::is_adjacent_pair(const StoreNode* use_store, const St
return pointer_def.is_adjacent_to_and_before(pointer_use);
}
bool MergePrimitiveStores::is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const {
// Check input values n1 and n2 can be merged and return the value order
MergePrimitiveStores::ValueOrder MergePrimitiveStores::find_adjacent_input_value_order(const Node* n1, const Node* n2,
const int memory_size) const {
// Pattern: [n1 = ConI, n2 = ConI]
if (n1->Opcode() == Op_ConI) {
return n2->Opcode() == Op_ConI;
if (n1->Opcode() == Op_ConI && n2->Opcode() == Op_ConI) {
return ValueOrder::Const;
}
// Pattern: [n1 = base >> shift, n2 = base >> (shift + memory_size)]
#ifndef VM_LITTLE_ENDIAN
// Pattern: [n1 = base >> (shift + memory_size), n2 = base >> shift]
// Swapping n1 with n2 gives same pattern as on little endian platforms.
swap(n1, n2);
#endif // !VM_LITTLE_ENDIAN
Node const* base_n2;
Node const *base_n2;
jint shift_n2;
if (!is_con_RShift(n2, base_n2, shift_n2)) {
return false;
if (!is_con_RShift(n2, base_n2, shift_n2, _phase)) {
return ValueOrder::NotAdjacent;
}
if (n1->Opcode() == Op_ConvL2I) {
// look through
n1 = n1->in(1);
}
Node const* base_n1;
Node const *base_n1;
jint shift_n1;
if (n1 == base_n2) {
// n1 = base = base >> 0
base_n1 = n1;
shift_n1 = 0;
} else if (!is_con_RShift(n1, base_n1, shift_n1)) {
return false;
if (!is_con_RShift(n1, base_n1, shift_n1, _phase)) {
return ValueOrder::NotAdjacent;
}
int bits_per_store = memory_size * 8;
if (base_n1 != base_n2 ||
shift_n1 + bits_per_store != shift_n2 ||
abs(shift_n1 - shift_n2) != bits_per_store ||
shift_n1 % bits_per_store != 0) {
return false;
// Values are not adjacent
return ValueOrder::NotAdjacent;
}
// both load from same value with correct shift
return true;
// Detect value order
#ifdef VM_LITTLE_ENDIAN
return shift_n1 < shift_n2 ? ValueOrder::Platform // Pattern: [n1 = base >> shift, n2 = base >> (shift + memory_size)]
: ValueOrder::Reverse; // Pattern: [n1 = base >> (shift + memory_size), n2 = base >> shift]
#else
return shift_n1 > shift_n2 ? ValueOrder::Platform // Pattern: [n1 = base >> (shift + memory_size), n2 = base >> shift]
: ValueOrder::Reverse; // Pattern: [n1 = base >> shift, n2 = base >> (shift + memory_size)]
#endif
}
bool MergePrimitiveStores::is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const {
ValueOrder input_value_order = find_adjacent_input_value_order(n1, n2, memory_size);
switch (input_value_order) {
case ValueOrder::NotAdjacent:
return false;
case ValueOrder::Reverse:
if (memory_size != 1 ||
!Matcher::match_rule_supported(Op_ReverseBytesS) ||
!Matcher::match_rule_supported(Op_ReverseBytesI) ||
!Matcher::match_rule_supported(Op_ReverseBytesL)) {
// ReverseBytes are not supported by platform
return false;
}
// fall-through.
case ValueOrder::Const:
case ValueOrder::Platform:
if (_value_order == ValueOrder::Unknown) {
// Initial state is Unknown, and we find a valid input value order
return true;
}
// The value order can not be changed
return _value_order == input_value_order;
case ValueOrder::Unknown:
default:
ShouldNotReachHere();
}
return false;
}
// Detect pattern: n = base_out >> shift_out
bool MergePrimitiveStores::is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out) {
bool MergePrimitiveStores::is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out, PhaseGVN* phase) {
assert(n != nullptr, "precondition");
int opc = n->Opcode();
@ -2997,6 +3052,14 @@ bool MergePrimitiveStores::is_con_RShift(const Node* n, Node const*& base_out, j
// The shift must be positive:
return shift_out >= 0;
}
if (phase->type(n)->isa_int() != nullptr ||
phase->type(n)->isa_long() != nullptr) {
// (base >> 0)
base_out = n;
shift_out = 0;
return true;
}
return false;
}
@ -3163,6 +3226,7 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
Node* first = merge_list.at(merge_list.size()-1);
Node* merged_input_value = nullptr;
if (_store->in(MemNode::ValueIn)->Opcode() == Op_ConI) {
assert(_value_order == ValueOrder::Const, "must match");
// Pattern: [ConI, ConI, ...] -> new constant
jlong con = 0;
jlong bits_per_store = _store->memory_size() * 8;
@ -3179,6 +3243,7 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
}
merged_input_value = _phase->longcon(con);
} else {
assert(_value_order == ValueOrder::Platform || _value_order == ValueOrder::Reverse, "must match");
// Pattern: [base >> 24, base >> 16, base >> 8, base] -> base
// | |
// _store first
@ -3189,10 +3254,13 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
// `_store` and `first` are swapped in the diagram above
swap(hi, lo);
#endif // !VM_LITTLE_ENDIAN
if (_value_order == ValueOrder::Reverse) {
swap(hi, lo);
}
Node const* hi_base;
jint hi_shift;
merged_input_value = lo;
bool is_true = is_con_RShift(hi, hi_base, hi_shift);
bool is_true = is_con_RShift(hi, hi_base, hi_shift, _phase);
assert(is_true, "must detect con RShift");
if (merged_input_value != hi_base && merged_input_value->Opcode() == Op_ConvL2I) {
// look through
@ -3218,6 +3286,17 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
(_phase->type(merged_input_value)->isa_long() != nullptr && new_memory_size == 8),
"merged_input_value is either int or long, and new_memory_size is small enough");
if (_value_order == ValueOrder::Reverse) {
assert(_store->memory_size() == 1, "only implemented for bytes");
if (new_memory_size == 8) {
merged_input_value = _phase->transform(new ReverseBytesLNode(merged_input_value));
} else if (new_memory_size == 4) {
merged_input_value = _phase->transform(new ReverseBytesINode(merged_input_value));
} else {
assert(new_memory_size == 2, "sanity check");
merged_input_value = _phase->transform(new ReverseBytesSNode(merged_input_value));
}
}
return merged_input_value;
}

View File

@ -33,7 +33,7 @@ import java.util.Random;
/*
* @test
* @bug 8318446 8331054 8331311 8335392
* @bug 8318446 8331054 8331311 8335392 8347405
* @summary Test merging of consecutive stores
* @modules java.base/jdk.internal.misc
* @library /test/lib /
@ -42,7 +42,7 @@ import java.util.Random;
/*
* @test
* @bug 8318446 8331054 8331311 8335392
* @bug 8318446 8331054 8331311 8335392 8347405
* @summary Test merging of consecutive stores
* @modules java.base/jdk.internal.misc
* @library /test/lib /
@ -724,10 +724,12 @@ public class TestMergeStores {
@IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"little-endian", "true"})
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
@IR(counts = { IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.REVERSE_BYTES_L, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
static Object[] test2a(byte[] a, int offset, long v) {
a[offset + 0] = (byte)(v >> 0);
@ -755,10 +757,12 @@ public class TestMergeStores {
@IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"little-endian", "true"})
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.REVERSE_BYTES_L, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
static Object[] test2c(byte[] a, int offset, long v) {
storeLongLE(a, offset, v);
@ -797,11 +801,13 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIfPlatform = {"little-endian", "true"})
@IR(counts = { IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.REVERSE_BYTES_L, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
@ -828,11 +834,13 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIfPlatform = {"little-endian", "true"})
@IR(counts = { IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.REVERSE_BYTES_L, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
@ -873,13 +881,18 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2"},
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"little-endian", "true"})
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.REVERSE_BYTES_I, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
static Object[] test3a(byte[] a, int offset, long v) {
a[offset + 0] = (byte)(v >> 0);
@ -907,11 +920,13 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIfPlatform = {"little-endian", "true"})
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.REVERSE_BYTES_I, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
@ -956,10 +971,12 @@ public class TestMergeStores {
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"little-endian", "true"})
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "12",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // Stores of constants can be merged
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "4", // Unmerged stores: offset + (2,3,16) , and 1 for uncommon trap
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "3", // 1([+0,+1]) for platform order and 2([+4,+5], [+14,+15]) for reverse order
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2", // 1([+6,+9]) for platform order and 1([+10,+13]) for reverse order
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.REVERSE_BYTES_I, "1",
IRNode.REVERSE_BYTES_S, "2"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
static Object[] test4a(byte[] a, int offset, long v1, int v2, short v3, byte v4) {
@ -1006,12 +1023,14 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "12",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // Stores of constants can be merged
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "4", // Unmerged stores: offset + (2,3,16) , and 1 for uncommon trap
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "3", // 1([+0,+1]) for platform order and 2([+4,+5], [+14,+15]) for reverse order
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2", // 1([+6,+9]) for platform order and 1([+10,+13]) for reverse order
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.REVERSE_BYTES_I, "1",
IRNode.REVERSE_BYTES_S, "2"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"little-endian", "true"})
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "4", // 3 (+ 1 for uncommon trap)
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "3",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2",
@ -1783,10 +1802,12 @@ public class TestMergeStores {
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1"}, // expect merged
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"little-endian", "true"})
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // for RangeCheck trap
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // expect merged
IRNode.REVERSE_BYTES_L, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatform = {"big-endian", "true"})
static Object[] test500a(byte[] a, int offset, long v) {
int idx = 0;
@ -1897,11 +1918,13 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // for RangeCheck trap
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIfPlatform = {"little-endian", "true"})
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // expect merged
IRNode.REVERSE_BYTES_L, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1", // for RangeCheck trap
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
@ -1932,11 +1955,13 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "7",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIfPlatform = {"little-endian", "true"})
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.REVERSE_BYTES_S, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "7",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
@ -1967,11 +1992,13 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "8",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "7",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIfPlatform = {"little-endian", "true"})
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.REVERSE_BYTES_S, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "7",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
@ -2168,11 +2195,13 @@ public class TestMergeStores {
}
@Test
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "6",
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0"},
applyIfPlatform = {"little-endian", "true"})
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",
IRNode.STORE_L_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.REVERSE_BYTES_I, "1"},
applyIf = {"UseUnalignedAccesses", "true"},
applyIfPlatformAnd = {"little-endian", "true", "riscv64", "false"}) // Exclude riscv64 where ReverseBytes is only conditionally supported
@IR(counts = {IRNode.STORE_B_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "2",
IRNode.STORE_C_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "0",
IRNode.STORE_I_OF_CLASS, "byte\\\\[int:>=0] \\\\(java/lang/Cloneable,java/io/Serializable\\\\)", "1",

View File

@ -1520,6 +1520,26 @@ public class IRNode {
vectorNode(REPLICATE_D, "Replicate", TYPE_DOUBLE);
}
public static final String REVERSE_BYTES_I = PREFIX + "REVERSE_BYTES_I" + POSTFIX;
static {
beforeMatchingNameRegex(REVERSE_BYTES_I, "ReverseBytesI");
}
public static final String REVERSE_BYTES_L = PREFIX + "REVERSE_BYTES_L" + POSTFIX;
static {
beforeMatchingNameRegex(REVERSE_BYTES_L, "ReverseBytesL");
}
public static final String REVERSE_BYTES_S = PREFIX + "REVERSE_BYTES_S" + POSTFIX;
static {
beforeMatchingNameRegex(REVERSE_BYTES_S, "ReverseBytesS");
}
public static final String REVERSE_BYTES_US = PREFIX + "REVERSE_BYTES_US" + POSTFIX;
static {
beforeMatchingNameRegex(REVERSE_BYTES_US, "ReverseBytesUS");
}
public static final String REVERSE_BYTES_VB = VECTOR_PREFIX + "REVERSE_BYTES_VB" + POSTFIX;
static {
vectorNode(REVERSE_BYTES_VB, "ReverseBytesV", TYPE_BYTE);