Skip to content

Commit 5928209

Browse files
kuaiweireinrich
authored andcommitted
8347405: MergeStores with reverse bytes order value
Co-authored-by: Richard Reingruber <rrich@openjdk.org> Reviewed-by: epeter, thartmann
1 parent f984c2b commit 5928209

File tree

3 files changed

+212
-84
lines changed

3 files changed

+212
-84
lines changed

src/hotspot/share/opto/memnode.cpp

Lines changed: 111 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2774,12 +2774,33 @@ class MergePrimitiveStores : public StackObj {
27742774
private:
27752775
PhaseGVN* const _phase;
27762776
StoreNode* const _store;
2777+
// State machine with initial state Unknown
2778+
// Allowed transitions:
2779+
// Unknown -> Const
2780+
// Unknown -> Platform
2781+
// Unknown -> Reverse
2782+
// Unknown -> NotAdjacent
2783+
// Const -> Const
2784+
// Const -> NotAdjacent
2785+
// Platform -> Platform
2786+
// Platform -> NotAdjacent
2787+
// Reverse -> Reverse
2788+
// Reverse -> NotAdjacent
2789+
// NotAdjacent -> NotAdjacent
2790+
enum ValueOrder : uint8_t {
2791+
Unknown, // Initial state
2792+
Const, // Input values are const
2793+
Platform, // Platform order
2794+
Reverse, // Reverse platform order
2795+
NotAdjacent // Not adjacent
2796+
};
2797+
ValueOrder _value_order;
27772798

27782799
NOT_PRODUCT( const CHeapBitMap &_trace_tags; )
27792800

27802801
public:
27812802
MergePrimitiveStores(PhaseGVN* phase, StoreNode* store) :
2782-
_phase(phase), _store(store)
2803+
_phase(phase), _store(store), _value_order(ValueOrder::Unknown)
27832804
NOT_PRODUCT( COMMA _trace_tags(Compile::current()->directive()->trace_merge_stores_tags()) )
27842805
{}
27852806

@@ -2789,7 +2810,7 @@ class MergePrimitiveStores : public StackObj {
27892810
bool is_compatible_store(const StoreNode* other_store) const;
27902811
bool is_adjacent_pair(const StoreNode* use_store, const StoreNode* def_store) const;
27912812
bool is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const;
2792-
static bool is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out);
2813+
static bool is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out, PhaseGVN* phase);
27932814
enum CFGStatus { SuccessNoRangeCheck, SuccessWithRangeCheck, Failure };
27942815
static CFGStatus cfg_status_for_pair(const StoreNode* use_store, const StoreNode* def_store);
27952816

@@ -2825,6 +2846,7 @@ class MergePrimitiveStores : public StackObj {
28252846
#endif
28262847
};
28272848

2849+
enum ValueOrder find_adjacent_input_value_order(const Node* n1, const Node* n2, const int memory_size) const;
28282850
Status find_adjacent_use_store(const StoreNode* def_store) const;
28292851
Status find_adjacent_def_store(const StoreNode* use_store) const;
28302852
Status find_use_store(const StoreNode* def_store) const;
@@ -2886,10 +2908,17 @@ StoreNode* MergePrimitiveStores::run() {
28862908
// Check if we can merge with at least one def, so that we have at least 2 stores to merge.
28872909
Status status_def = find_adjacent_def_store(_store);
28882910
NOT_PRODUCT( if (is_trace_basic()) { tty->print("[TraceMergeStores] expect def: "); status_def.print_on(tty); })
2889-
if (status_def.found_store() == nullptr) {
2911+
Node* def_store = status_def.found_store();
2912+
if (def_store == nullptr) {
28902913
return nullptr;
28912914
}
28922915

2916+
// Initialize value order
2917+
_value_order = find_adjacent_input_value_order(def_store->in(MemNode::ValueIn),
2918+
_store->in(MemNode::ValueIn),
2919+
_store->memory_size());
2920+
assert(_value_order != ValueOrder::NotAdjacent && _value_order != ValueOrder::Unknown, "Order should be checked");
2921+
28932922
ResourceMark rm;
28942923
Node_List merge_list;
28952924
collect_merge_list(merge_list);
@@ -2936,49 +2965,75 @@ bool MergePrimitiveStores::is_adjacent_pair(const StoreNode* use_store, const St
29362965
return pointer_def.is_adjacent_to_and_before(pointer_use);
29372966
}
29382967

2939-
bool MergePrimitiveStores::is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const {
2968+
// Check input values n1 and n2 can be merged and return the value order
2969+
MergePrimitiveStores::ValueOrder MergePrimitiveStores::find_adjacent_input_value_order(const Node* n1, const Node* n2,
2970+
const int memory_size) const {
29402971
// Pattern: [n1 = ConI, n2 = ConI]
2941-
if (n1->Opcode() == Op_ConI) {
2942-
return n2->Opcode() == Op_ConI;
2972+
if (n1->Opcode() == Op_ConI && n2->Opcode() == Op_ConI) {
2973+
return ValueOrder::Const;
29432974
}
29442975

2945-
// Pattern: [n1 = base >> shift, n2 = base >> (shift + memory_size)]
2946-
#ifndef VM_LITTLE_ENDIAN
2947-
// Pattern: [n1 = base >> (shift + memory_size), n2 = base >> shift]
2948-
// Swapping n1 with n2 gives same pattern as on little endian platforms.
2949-
swap(n1, n2);
2950-
#endif // !VM_LITTLE_ENDIAN
2951-
Node const* base_n2;
2976+
Node const *base_n2;
29522977
jint shift_n2;
2953-
if (!is_con_RShift(n2, base_n2, shift_n2)) {
2954-
return false;
2978+
if (!is_con_RShift(n2, base_n2, shift_n2, _phase)) {
2979+
return ValueOrder::NotAdjacent;
29552980
}
2956-
if (n1->Opcode() == Op_ConvL2I) {
2957-
// look through
2958-
n1 = n1->in(1);
2959-
}
2960-
Node const* base_n1;
2981+
Node const *base_n1;
29612982
jint shift_n1;
2962-
if (n1 == base_n2) {
2963-
// n1 = base = base >> 0
2964-
base_n1 = n1;
2965-
shift_n1 = 0;
2966-
} else if (!is_con_RShift(n1, base_n1, shift_n1)) {
2967-
return false;
2983+
if (!is_con_RShift(n1, base_n1, shift_n1, _phase)) {
2984+
return ValueOrder::NotAdjacent;
29682985
}
2986+
29692987
int bits_per_store = memory_size * 8;
29702988
if (base_n1 != base_n2 ||
2971-
shift_n1 + bits_per_store != shift_n2 ||
2989+
abs(shift_n1 - shift_n2) != bits_per_store ||
29722990
shift_n1 % bits_per_store != 0) {
2973-
return false;
2991+
// Values are not adjacent
2992+
return ValueOrder::NotAdjacent;
29742993
}
29752994

2976-
// both load from same value with correct shift
2977-
return true;
2995+
// Detect value order
2996+
#ifdef VM_LITTLE_ENDIAN
2997+
return shift_n1 < shift_n2 ? ValueOrder::Platform // Pattern: [n1 = base >> shift, n2 = base >> (shift + memory_size)]
2998+
: ValueOrder::Reverse; // Pattern: [n1 = base >> (shift + memory_size), n2 = base >> shift]
2999+
#else
3000+
return shift_n1 > shift_n2 ? ValueOrder::Platform // Pattern: [n1 = base >> (shift + memory_size), n2 = base >> shift]
3001+
: ValueOrder::Reverse; // Pattern: [n1 = base >> shift, n2 = base >> (shift + memory_size)]
3002+
#endif
3003+
}
3004+
3005+
bool MergePrimitiveStores::is_adjacent_input_pair(const Node* n1, const Node* n2, const int memory_size) const {
3006+
ValueOrder input_value_order = find_adjacent_input_value_order(n1, n2, memory_size);
3007+
3008+
switch (input_value_order) {
3009+
case ValueOrder::NotAdjacent:
3010+
return false;
3011+
case ValueOrder::Reverse:
3012+
if (memory_size != 1 ||
3013+
!Matcher::match_rule_supported(Op_ReverseBytesS) ||
3014+
!Matcher::match_rule_supported(Op_ReverseBytesI) ||
3015+
!Matcher::match_rule_supported(Op_ReverseBytesL)) {
3016+
// ReverseBytes are not supported by platform
3017+
return false;
3018+
}
3019+
// fall-through.
3020+
case ValueOrder::Const:
3021+
case ValueOrder::Platform:
3022+
if (_value_order == ValueOrder::Unknown) {
3023+
// Initial state is Unknown, and we find a valid input value order
3024+
return true;
3025+
}
3026+
// The value order can not be changed
3027+
return _value_order == input_value_order;
3028+
case ValueOrder::Unknown:
3029+
default:
3030+
ShouldNotReachHere();
3031+
}
3032+
return false;
29783033
}
29793034

29803035
// Detect pattern: n = base_out >> shift_out
2981-
bool MergePrimitiveStores::is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out) {
3036+
bool MergePrimitiveStores::is_con_RShift(const Node* n, Node const*& base_out, jint& shift_out, PhaseGVN* phase) {
29823037
assert(n != nullptr, "precondition");
29833038

29843039
int opc = n->Opcode();
@@ -2997,6 +3052,14 @@ bool MergePrimitiveStores::is_con_RShift(const Node* n, Node const*& base_out, j
29973052
// The shift must be positive:
29983053
return shift_out >= 0;
29993054
}
3055+
3056+
if (phase->type(n)->isa_int() != nullptr ||
3057+
phase->type(n)->isa_long() != nullptr) {
3058+
// (base >> 0)
3059+
base_out = n;
3060+
shift_out = 0;
3061+
return true;
3062+
}
30003063
return false;
30013064
}
30023065

@@ -3163,6 +3226,7 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
31633226
Node* first = merge_list.at(merge_list.size()-1);
31643227
Node* merged_input_value = nullptr;
31653228
if (_store->in(MemNode::ValueIn)->Opcode() == Op_ConI) {
3229+
assert(_value_order == ValueOrder::Const, "must match");
31663230
// Pattern: [ConI, ConI, ...] -> new constant
31673231
jlong con = 0;
31683232
jlong bits_per_store = _store->memory_size() * 8;
@@ -3179,6 +3243,7 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
31793243
}
31803244
merged_input_value = _phase->longcon(con);
31813245
} else {
3246+
assert(_value_order == ValueOrder::Platform || _value_order == ValueOrder::Reverse, "must match");
31823247
// Pattern: [base >> 24, base >> 16, base >> 8, base] -> base
31833248
// | |
31843249
// _store first
@@ -3189,10 +3254,13 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
31893254
// `_store` and `first` are swapped in the diagram above
31903255
swap(hi, lo);
31913256
#endif // !VM_LITTLE_ENDIAN
3257+
if (_value_order == ValueOrder::Reverse) {
3258+
swap(hi, lo);
3259+
}
31923260
Node const* hi_base;
31933261
jint hi_shift;
31943262
merged_input_value = lo;
3195-
bool is_true = is_con_RShift(hi, hi_base, hi_shift);
3263+
bool is_true = is_con_RShift(hi, hi_base, hi_shift, _phase);
31963264
assert(is_true, "must detect con RShift");
31973265
if (merged_input_value != hi_base && merged_input_value->Opcode() == Op_ConvL2I) {
31983266
// look through
@@ -3218,6 +3286,17 @@ Node* MergePrimitiveStores::make_merged_input_value(const Node_List& merge_list)
32183286
(_phase->type(merged_input_value)->isa_long() != nullptr && new_memory_size == 8),
32193287
"merged_input_value is either int or long, and new_memory_size is small enough");
32203288

3289+
if (_value_order == ValueOrder::Reverse) {
3290+
assert(_store->memory_size() == 1, "only implemented for bytes");
3291+
if (new_memory_size == 8) {
3292+
merged_input_value = _phase->transform(new ReverseBytesLNode(merged_input_value));
3293+
} else if (new_memory_size == 4) {
3294+
merged_input_value = _phase->transform(new ReverseBytesINode(merged_input_value));
3295+
} else {
3296+
assert(new_memory_size == 2, "sanity check");
3297+
merged_input_value = _phase->transform(new ReverseBytesSNode(merged_input_value));
3298+
}
3299+
}
32213300
return merged_input_value;
32223301
}
32233302

0 commit comments

Comments
 (0)