diff --git a/src/hotspot/cpu/x86/peephole_x86_64.cpp b/src/hotspot/cpu/x86/peephole_x86_64.cpp index ab58c566ea4..8c956aeb053 100644 --- a/src/hotspot/cpu/x86/peephole_x86_64.cpp +++ b/src/hotspot/cpu/x86/peephole_x86_64.cpp @@ -26,6 +26,7 @@ #ifdef COMPILER2 #include "peephole_x86_64.hpp" +#include "adfiles/ad_x86.hpp" // This function transforms the shapes // mov d, s1; add d, s2 into @@ -132,6 +133,109 @@ bool lea_coalesce_helper(Block* block, int block_index, PhaseCFG* cfg_, PhaseReg return true; } +// This helper func takes a condition and returns the flags that need to be set for the condition +// It uses the same flags as the test instruction, so if the e.g. the overflow bit is required, +// this func returns clears_overflow, as that is what the test instruction does and what the downstream path expects +juint map_condition_to_required_test_flags(Assembler::Condition condition) { + switch (condition) { + case Assembler::Condition::zero: // Same value as equal + case Assembler::Condition::notZero: // Same value as notEqual + return Node::PD::Flag_sets_zero_flag; + case Assembler::Condition::less: + case Assembler::Condition::greaterEqual: + return Node::PD::Flag_sets_sign_flag | Node::PD::Flag_clears_overflow_flag; + case Assembler::Condition::lessEqual: + case Assembler::Condition::greater: + return Node::PD::Flag_sets_sign_flag | Node::PD::Flag_clears_overflow_flag | Node::PD::Flag_sets_zero_flag; + case Assembler::Condition::below: // Same value as carrySet + case Assembler::Condition::aboveEqual: // Same value as carryClear + return Node::PD::Flag_clears_carry_flag; + case Assembler::Condition::belowEqual: + case Assembler::Condition::above: + return Node::PD::Flag_clears_carry_flag | Node::PD::Flag_sets_zero_flag; + case Assembler::Condition::overflow: + case Assembler::Condition::noOverflow: + return Node::PD::Flag_clears_overflow_flag; + case Assembler::Condition::negative: + case Assembler::Condition::positive: + return Node::PD::Flag_sets_sign_flag; + case Assembler::Condition::parity: + case Assembler::Condition::noParity: + return Node::PD::Flag_sets_parity_flag; + default: + ShouldNotReachHere(); + return 0; + } +} + + +// This function removes the TEST instruction when it detected shapes likes AND r1, r2; TEST r1, r1 +// It checks the required EFLAGS for the downstream instructions of the TEST +// and removes the TEST if the preceding instructions already sets all these flags +bool Peephole::test_may_remove(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, + MachNode* (*new_root)(), uint inst0_rule) { + MachNode* test_to_check = block->get_node(block_index)->as_Mach(); + assert(test_to_check->rule() == inst0_rule, "sanity"); + + Node* inst1 = test_to_check->in(1); + // Only remove test if the block order is inst1 -> MachProjNode (because the node to match must specify KILL cr) -> test_to_check + // So inst1 must be at index - 2 + if (block_index < 2 || block->get_node(block_index - 2) != inst1) { + return false; + } + if (inst1 != nullptr) { + MachNode* prevNode = inst1->isa_Mach(); + if (prevNode != nullptr) { + // Includes other flags as well, but that doesn't matter here + juint all_node_flags = prevNode->flags(); + if (all_node_flags == 0) { + // We can return early - there is no way the test can be removed, the preceding node does not set any flags + return false; + } + juint required_flags = 0; + // Search for the uses of the node and compute which flags are required + for (DUIterator_Fast imax, i = test_to_check->fast_outs(imax); i < imax; i++) { + MachNode* node_out = test_to_check->fast_out(i)->isa_Mach(); + bool found_correct_oper = false; + for (uint16_t j = 0; j < node_out->_num_opnds; ++j) { + MachOper* operand = node_out->_opnds[j]; + if (operand->opcode() == cmpOp_rule || operand->opcode() == cmpOpU_rule) { + auto condition = static_cast(operand->ccode()); + juint flags_for_inst = map_condition_to_required_test_flags(condition); + required_flags = required_flags | flags_for_inst; + found_correct_oper = true; + break; + } + } + if (!found_correct_oper) { + // We could not find one the required flags for one of the dependencies. Keep the test as it might set flags needed for that node + return false; + } + } + assert(required_flags != 0, "No flags required, should be impossible!"); + bool sets_all_required_flags = (required_flags & ~all_node_flags) == 0; + if (sets_all_required_flags) { + // All flags are covered are clear to remove this test + MachProjNode* machProjNode = block->get_node(block_index - 1)->isa_MachProj(); + assert(machProjNode != nullptr, "Expected a MachProj node here!"); + assert(ra_->get_reg_first(machProjNode) == ra_->get_reg_first(test_to_check), "Test must operate on the same register as its replacement"); + + // Remove the original test node and replace it with the pseudo test node. The AND node already sets ZF + test_to_check->replace_by(machProjNode); + + // Modify the block + test_to_check->set_removed(); + block->remove_node(block_index); + + // Modify the control flow + cfg_->map_node_to_block(test_to_check, nullptr); + return true; + } + } + } + return false; +} + bool Peephole::lea_coalesce_reg(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, MachNode* (*new_root)(), uint inst0_rule) { return lea_coalesce_helper(block, block_index, cfg_, ra_, new_root, inst0_rule, false); diff --git a/src/hotspot/cpu/x86/peephole_x86_64.hpp b/src/hotspot/cpu/x86/peephole_x86_64.hpp index 65227820173..deb53f0dfd7 100644 --- a/src/hotspot/cpu/x86/peephole_x86_64.hpp +++ b/src/hotspot/cpu/x86/peephole_x86_64.hpp @@ -34,6 +34,8 @@ public: MachNode* (*new_root)(), uint inst0_rule); static bool lea_coalesce_imm(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, MachNode* (*new_root)(), uint inst0_rule); + static bool test_may_remove(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, + MachNode* (*new_root)(), uint inst0_rule); }; #endif // CPU_X86_PEEPHOLE_X86_64_HPP diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 61ab92326b2..a7a982edd07 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1254,8 +1254,18 @@ static inline bool is_clz_non_subword_predicate_evex(BasicType bt, int vlen_byte class Node::PD { public: enum NodeFlags { - Flag_intel_jcc_erratum = Node::_last_flag << 1, - _last_flag = Flag_intel_jcc_erratum + Flag_intel_jcc_erratum = Node::_last_flag << 1, + Flag_sets_carry_flag = Node::_last_flag << 2, + Flag_sets_parity_flag = Node::_last_flag << 3, + Flag_sets_zero_flag = Node::_last_flag << 4, + Flag_sets_overflow_flag = Node::_last_flag << 5, + Flag_sets_sign_flag = Node::_last_flag << 6, + Flag_clears_carry_flag = Node::_last_flag << 7, + Flag_clears_parity_flag = Node::_last_flag << 8, + Flag_clears_zero_flag = Node::_last_flag << 9, + Flag_clears_overflow_flag = Node::_last_flag << 10, + Flag_clears_sign_flag = Node::_last_flag << 11, + _last_flag = Flag_clears_sign_flag }; }; diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 16733dbe1d1..5b1e206ae9a 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -7649,7 +7649,7 @@ instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); effect(KILL cr); - + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addl $dst, $src\t# int" %} ins_encode %{ __ addl($dst$$Register, $src$$Register); @@ -7661,6 +7661,7 @@ instruct addI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addl $dst, $src\t# int" %} ins_encode %{ @@ -7673,6 +7674,7 @@ instruct addI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (AddI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addl $dst, $src\t# int" %} @@ -7686,6 +7688,7 @@ instruct addI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AddI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addl $dst, $src\t# int" %} @@ -7699,6 +7702,8 @@ instruct addI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AddI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + ins_cost(125); // XXX format %{ "addl $dst, $src\t# int" %} @@ -7819,6 +7824,7 @@ instruct addL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (AddL dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# long" %} ins_encode %{ @@ -7831,6 +7837,7 @@ instruct addL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (AddL dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# long" %} ins_encode %{ @@ -7843,6 +7850,7 @@ instruct addL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (AddL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addq $dst, $src\t# long" %} @@ -7856,6 +7864,7 @@ instruct addL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AddL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addq $dst, $src\t# long" %} @@ -7869,6 +7878,7 @@ instruct addL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AddL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(125); // XXX format %{ "addq $dst, $src\t# long" %} @@ -7989,6 +7999,7 @@ instruct addP_rReg(rRegP dst, rRegL src, rFlagsReg cr) %{ match(Set dst (AddP dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# ptr" %} ins_encode %{ @@ -8001,6 +8012,7 @@ instruct addP_rReg_imm(rRegP dst, immL32 src, rFlagsReg cr) %{ match(Set dst (AddP dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# ptr" %} ins_encode %{ @@ -8554,6 +8566,7 @@ instruct subI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (SubI dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "subl $dst, $src\t# int" %} ins_encode %{ @@ -8566,6 +8579,7 @@ instruct subI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (SubI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subl $dst, $src\t# int" %} @@ -8579,6 +8593,7 @@ instruct subI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (SubI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subl $dst, $src\t# int" %} @@ -8592,6 +8607,7 @@ instruct subL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (SubL dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "subq $dst, $src\t# long" %} ins_encode %{ @@ -8604,6 +8620,7 @@ instruct subL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (SubL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subq $dst, $src\t# long" %} @@ -8617,6 +8634,7 @@ instruct subL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (SubL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subq $dst, $src\t# long" %} @@ -8643,6 +8661,7 @@ instruct negI_rReg(rRegI dst, immI_0 zero, rFlagsReg cr) %{ match(Set dst (SubI zero dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negl $dst\t# int" %} ins_encode %{ @@ -8655,6 +8674,7 @@ instruct negI_rReg_2(rRegI dst, rFlagsReg cr) %{ match(Set dst (NegI dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negl $dst\t# int" %} ins_encode %{ @@ -8667,6 +8687,7 @@ instruct negI_mem(memory dst, immI_0 zero, rFlagsReg cr) %{ match(Set dst (StoreI dst (SubI zero (LoadI dst)))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negl $dst\t# int" %} ins_encode %{ @@ -8679,6 +8700,7 @@ instruct negL_rReg(rRegL dst, immL0 zero, rFlagsReg cr) %{ match(Set dst (SubL zero dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negq $dst\t# long" %} ins_encode %{ @@ -8691,6 +8713,7 @@ instruct negL_rReg_2(rRegL dst, rFlagsReg cr) %{ match(Set dst (NegL dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negq $dst\t# int" %} ins_encode %{ @@ -8703,6 +8726,7 @@ instruct negL_mem(memory dst, immL0 zero, rFlagsReg cr) %{ match(Set dst (StoreL dst (SubL zero (LoadL dst)))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negq $dst\t# long" %} ins_encode %{ @@ -9184,6 +9208,7 @@ instruct sarI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) predicate(!VM_Version::supports_bmi2()); match(Set dst (RShiftI dst shift)); effect(KILL cr); + format %{ "sarl $dst, $shift" %} ins_encode %{ __ sarl($dst$$Register); @@ -9838,6 +9863,7 @@ instruct andI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AndI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andl $dst, $src\t# int" %} ins_encode %{ @@ -9914,6 +9940,7 @@ instruct andI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (AndI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andl $dst, $src\t# int" %} ins_encode %{ @@ -9927,6 +9954,7 @@ instruct andI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (AndI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andl $dst, $src\t# int" %} @@ -9941,6 +9969,7 @@ instruct andB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreB dst (AndI (LoadB dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andb $dst, $src\t# byte" %} @@ -9954,6 +9983,7 @@ instruct andI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AndI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andl $dst, $src\t# int" %} @@ -9968,6 +9998,7 @@ instruct andI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AndI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andl $dst, $src\t# int" %} @@ -9982,6 +10013,7 @@ instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1 match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andnl $dst, $src1, $src2" %} @@ -9996,6 +10028,7 @@ instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1 match(Set dst (AndI (XorI src1 minus_1) src2)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andnl $dst, $src1, $src2" %} @@ -10009,6 +10042,7 @@ instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI_0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndI (SubI imm_zero src) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsil $dst, $src" %} @@ -10022,6 +10056,7 @@ instruct blsiI_rReg_mem(rRegI dst, memory src, immI_0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsil $dst, $src" %} @@ -10037,6 +10072,7 @@ instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsmskl $dst, $src" %} @@ -10052,6 +10088,7 @@ instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (XorI (AddI src minus_1) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsmskl $dst, $src" %} @@ -10067,6 +10104,7 @@ instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (AndI (AddI src minus_1) src) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsrl $dst, $src" %} @@ -10082,6 +10120,7 @@ instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsrl $dst, $src" %} @@ -10099,6 +10138,7 @@ instruct orI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (OrI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orl $dst, $src\t# int" %} ins_encode %{ @@ -10112,6 +10152,7 @@ instruct orI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (OrI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orl $dst, $src\t# int" %} ins_encode %{ @@ -10125,6 +10166,7 @@ instruct orI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (OrI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orl $dst, $src\t# int" %} @@ -10139,6 +10181,7 @@ instruct orB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreB dst (OrI (LoadB dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orb $dst, $src\t# byte" %} @@ -10152,6 +10195,7 @@ instruct orI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (OrI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orl $dst, $src\t# int" %} @@ -10166,6 +10210,7 @@ instruct orI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (OrI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "orl $dst, $src\t# int" %} @@ -10181,6 +10226,7 @@ instruct xorI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (XorI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorl $dst, $src\t# int" %} ins_encode %{ @@ -10205,6 +10251,7 @@ instruct xorI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (XorI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorl $dst, $src\t# int" %} ins_encode %{ @@ -10218,6 +10265,7 @@ instruct xorI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (XorI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorl $dst, $src\t# int" %} @@ -10232,6 +10280,7 @@ instruct xorB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreB dst (XorI (LoadB dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorb $dst, $src\t# byte" %} @@ -10245,6 +10294,7 @@ instruct xorI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (XorI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorl $dst, $src\t# int" %} @@ -10259,6 +10309,7 @@ instruct xorI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (XorI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "xorl $dst, $src\t# int" %} @@ -10277,6 +10328,7 @@ instruct andL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (AndL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andq $dst, $src\t# long" %} ins_encode %{ @@ -10316,6 +10368,7 @@ instruct andL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (AndL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andq $dst, $src\t# long" %} ins_encode %{ @@ -10329,6 +10382,7 @@ instruct andL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (AndL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andq $dst, $src\t# long" %} @@ -10343,6 +10397,7 @@ instruct andL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AndL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andq $dst, $src\t# long" %} @@ -10357,6 +10412,7 @@ instruct andL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AndL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andq $dst, $src\t# long" %} @@ -10388,6 +10444,7 @@ instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1 match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andnq $dst, $src1, $src2" %} @@ -10402,6 +10459,7 @@ instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1 match(Set dst (AndL (XorL src1 minus_1) src2)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andnq $dst, $src1, $src2" %} @@ -10415,6 +10473,7 @@ instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndL (SubL imm_zero src) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsiq $dst, $src" %} @@ -10428,6 +10487,7 @@ instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsiq $dst, $src" %} @@ -10443,6 +10503,7 @@ instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsmskq $dst, $src" %} @@ -10458,6 +10519,7 @@ instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (XorL (AddL src minus_1) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsmskq $dst, $src" %} @@ -10473,6 +10535,7 @@ instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (AndL (AddL src minus_1) src) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsrq $dst, $src" %} @@ -10488,6 +10551,7 @@ instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsrq $dst, $src" %} @@ -10505,6 +10569,7 @@ instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (OrL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orq $dst, $src\t# long" %} ins_encode %{ @@ -10517,6 +10582,7 @@ instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr) instruct orL_rReg_castP2X(rRegL dst, any_RegP src, rFlagsReg cr) %{ match(Set dst (OrL dst (CastP2X src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orq $dst, $src\t# long" %} ins_encode %{ @@ -10531,6 +10597,7 @@ instruct orL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (OrL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orq $dst, $src\t# long" %} ins_encode %{ @@ -10544,6 +10611,7 @@ instruct orL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (OrL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orq $dst, $src\t# long" %} @@ -10558,6 +10626,7 @@ instruct orL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (OrL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orq $dst, $src\t# long" %} @@ -10572,6 +10641,7 @@ instruct orL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (OrL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "orq $dst, $src\t# long" %} @@ -10604,6 +10674,7 @@ instruct xorL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (XorL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorq $dst, $src\t# long" %} ins_encode %{ @@ -10628,6 +10699,7 @@ instruct xorL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (XorL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorq $dst, $src\t# long" %} ins_encode %{ @@ -10641,6 +10713,7 @@ instruct xorL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (XorL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorq $dst, $src\t# long" %} @@ -10655,6 +10728,7 @@ instruct xorL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (XorL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorq $dst, $src\t# long" %} @@ -10669,6 +10743,7 @@ instruct xorL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (XorL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "xorq $dst, $src\t# long" %} @@ -13863,6 +13938,24 @@ peephole peepreplace (leaL_rReg_immI2_peep()); %} +// These peephole rules matches instructions which set flags and are followed by a testI/L_reg +// The test instruction is redudanent in case the downstream instuctions (like JCC or CMOV) only use flags that are already set by the previous instruction + +//int variant +peephole +%{ + peepmatch (testI_reg); + peepprocedure (test_may_remove); +%} + +//long variant +peephole +%{ + peepmatch (testL_reg); + peepprocedure (test_may_remove); +%} + + //----------SMARTSPILL RULES--------------------------------------------------- // These must follow all instruction definitions as they use the names // defined in the instructions definitions. diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index 0ab306118d6..57c6b0c5a99 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -229,6 +229,7 @@ void ADLParser::instr_parse(void) { else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr); else if (!strcmp(ident, "size")) instr->_size = size_parse(instr); else if (!strcmp(ident, "effect")) effect_parse(instr); + else if (!strcmp(ident, "flag")) instr->_flag = flag_parse(instr); else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr); else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse(); else if (!strcmp(ident, "constraint")) { @@ -4126,6 +4127,46 @@ void ADLParser::effect_parse(InstructForm *instr) { } +//-------------------------------flag_parse------------------------------------ +Flag* ADLParser::flag_parse(InstructForm *instr) { + char* ident = nullptr; + Flag* result = nullptr; + + skipws(); // Skip whitespace + if (_curchar != '(') { + parse_err(SYNERR, "missing '(' in flag definition\n"); + return nullptr; + } + do { + next_char(); + skipws(); + if (_curchar == ')') break; + + ident = get_ident(); + if (ident == nullptr) { + parse_err(SYNERR, "flag name expected at %c\n", _curchar); + return nullptr; + } + Flag* newflag = new Flag(ident); + if (result == nullptr) result = newflag; + else result->append_flag(newflag); + if (_AD._adl_debug > 1) fprintf(stderr, "\tFlag Name: %s\n", ident); + skipws(); + } while (_curchar == ','); + if (_curchar != ')') parse_err(SYNERR, "missing ')'\n"); + else { + next_char(); // set current character position past the close paren + } + + // Debug Stuff + if (_curchar != ';') { + parse_err(SYNERR, "missing ';' in Flag definition\n"); + } + // Skip ';' + next_char(); + return result; +} + //------------------------------expand_parse----------------------------------- ExpandRule* ADLParser::expand_parse(InstructForm *instr) { char *ident, *ident2; diff --git a/src/hotspot/share/adlc/adlparse.hpp b/src/hotspot/share/adlc/adlparse.hpp index 2d244fdf4cb..e5873ef29c7 100644 --- a/src/hotspot/share/adlc/adlparse.hpp +++ b/src/hotspot/share/adlc/adlparse.hpp @@ -47,6 +47,7 @@ class Encode; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class Constraint; class ConstructRule; @@ -177,6 +178,7 @@ protected: FormatRule *format_parse(void); // Parse format rule FormatRule *template_parse(void); // Parse format rule void effect_parse(InstructForm *instr); // Parse effect rule + Flag *flag_parse(InstructForm *instr); // Parse flag rule ExpandRule *expand_parse(InstructForm *instr); // Parse expand rule RewriteRule *rewrite_parse(void); // Parse rewrite rule Constraint *constraint_parse(void); // Parse constraint rule diff --git a/src/hotspot/share/adlc/forms.hpp b/src/hotspot/share/adlc/forms.hpp index eb0b1acfe15..c3dd85eb98b 100644 --- a/src/hotspot/share/adlc/forms.hpp +++ b/src/hotspot/share/adlc/forms.hpp @@ -54,6 +54,7 @@ class MatchRule; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class ConstructRule; class FormatRule; @@ -237,6 +238,7 @@ public: EXP, REW, EFF, + FLG, RDEF, RCL, ACL, diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp index 467076eb1b7..1a2b5dadd30 100644 --- a/src/hotspot/share/adlc/formsopt.hpp +++ b/src/hotspot/share/adlc/formsopt.hpp @@ -44,6 +44,7 @@ class MatchRule; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class ConstructRule; class FormatRule; diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index be4ee3a3acf..92f12e275a0 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -52,6 +52,7 @@ InstructForm::InstructForm(const char *id, bool ideal_only) _format = nullptr; _peephole = nullptr; _ins_pipe = nullptr; + _flag = nullptr; _uniq_idx = nullptr; _num_uniq = 0; _cisc_spill_operand = Not_cisc_spillable;// Which operand may cisc-spill @@ -86,6 +87,7 @@ InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule) _format = instr->_format; _peephole = instr->_peephole; _ins_pipe = instr->_ins_pipe; + _flag = instr->_flag; _uniq_idx = instr->_uniq_idx; _num_uniq = instr->_num_uniq; _cisc_spill_operand = Not_cisc_spillable; // Which operand may cisc-spill @@ -1893,6 +1895,34 @@ void Effect::output(FILE *fp) { // Write info to output files fprintf(fp,"Effect: %s\n", (_name?_name:"")); } +//---------------------------------Flag---------------------------------------- +Flag::Flag(const char *name) : _name(name), _next(nullptr) { + _ftype = Form::FLG; +} + +Flag::~Flag() { +} + +void Flag::append_flag(Flag *next_flag) { + if( _next == nullptr ) { + _next = next_flag; + } else { + _next->append_flag( next_flag ); + } +} + +Flag* Flag::next() { + return _next; +} + +void Flag::dump() { + output(stderr); +} + +void Flag::output(FILE *fp) { // Write info to output files + fprintf(fp,"Flag: %s\n", (_name?_name:"")); +} + //------------------------------ExpandRule------------------------------------- ExpandRule::ExpandRule() : _expand_instrs(), _newopconst(cmpstr, hashstr, Form::arena) { diff --git a/src/hotspot/share/adlc/formssel.hpp b/src/hotspot/share/adlc/formssel.hpp index 2036f7ed895..a55dcb73622 100644 --- a/src/hotspot/share/adlc/formssel.hpp +++ b/src/hotspot/share/adlc/formssel.hpp @@ -45,6 +45,7 @@ class MatchRule; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class ConstructRule; class FormatRule; @@ -108,6 +109,7 @@ public: FormatRule *_format; // Format for assembly generation Peephole *_peephole; // List of peephole rules for instruction const char *_ins_pipe; // Instruction Scheduling description class + Flag *_flag; // List of Flags that should be set by default for this node uint *_uniq_idx; // Indexes of unique operands uint _uniq_idx_length; // Length of _uniq_idx array @@ -515,6 +517,26 @@ public: void output(FILE *fp); // Write info to output files }; +//---------------------------------Flag---------------------------------------- +class Flag : public Form { +private: + Flag* _next; +public: + const char *_name; // Name of the flag (See Node:: or Node::Pd:: + + // Public Methods + Flag(const char *name); // Constructor + ~Flag(); // Destructor + + // Append a flag rule for the same instruction + void append_flag(Flag *next_flag); + + Flag* next(); + + void dump(); // Debug printer + void output(FILE *fp); // Write info to output files +}; + //------------------------------RewriteRule------------------------------------ class RewriteRule : public Form { private: diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 5276987eec4..d243589db44 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -1469,10 +1469,14 @@ void ArchDesc::definePeephole(FILE *fp, InstructForm *node) { // End of scope for this peephole's constraints fprintf(fp, " }\n"); } else { - const char* replace_inst = nullptr; - preplace->next_instruction(replace_inst); - // Generate the target instruction - fprintf(fp, " auto replacing = [](){ return static_cast(new %sNode()); };\n", replace_inst); + if (preplace != nullptr) { + const char *replace_inst = nullptr; + preplace->next_instruction(replace_inst); + // Generate the target instruction + fprintf(fp, " auto replacing = [](){ return static_cast(new %sNode()); };\n", replace_inst); + } else { + fprintf(fp, " auto replacing = nullptr;\n"); + } // Call the precedure fprintf(fp, " bool replacement = Peephole::%s(block, block_index, cfg_, ra_, replacing", pprocedure->name()); @@ -4010,6 +4014,22 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden fprintf(fp_cpp, " );\n"); // ##### } + if (inst->_flag != nullptr) { + Flag* node = inst->_flag; + const char* prefix = "Node::"; + bool node_flags_set = false; + do { + if (!node_flags_set) { + fprintf(fp_cpp, "%s node->add_flag(%s%s", indent, prefix, node->_name); + node_flags_set = true; + } else { + fprintf(fp_cpp, " | %s%s", prefix, node->_name); + } + } while ((node = node->next()) != nullptr); + if (node_flags_set) { + fprintf(fp_cpp, ");\n"); + } + } // Fill in the bottom_type where requested if (inst->captures_bottom_type(_globalNames)) { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestTestRemovalPeephole.java b/test/hotspot/jtreg/compiler/c2/irTests/TestTestRemovalPeephole.java new file mode 100644 index 00000000000..359493d86f4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestTestRemovalPeephole.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2023, 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. + */ + +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; +import java.util.Random; +import jdk.test.lib.Utils; + +/* + * @test + * @summary Test that unnessercary test instructions are not present in the final code + * @bug 8312213 + * @library /test/lib / + * @requires vm.compiler2.enabled + * @requires os.arch == "x86_64" | os.arch == "amd64" + * @run driver compiler.c2.irTests.TestTestRemovalPeephole + */ +public class TestTestRemovalPeephole { + static volatile boolean field; + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntAddtionEquals0(int x, int y) { + int result = x + y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntAddtionNotEquals0(int x, int y) { + int result = x + y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongAddtionEquals0(long x, long y) { + long result = x + y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongAddtionNotEquals0(long x, long y) { + long result = x + y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntOrEquals0(int x, int y) { + int result = x | y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntOrNotEquals0(int x, int y) { + int result = x | y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongOrEquals0(long x, long y) { + long result = x | y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongOrNotEquals0(long x, long y) { + long result = x | y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntOrGreater0(int x, int y) { + int result = x | y; + if (result > 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongOrGreater0(long x, long y) { + long result = x | y; + if (result > 0) { + field = true; + return true; + } + return false; + } + + @DontCompile + public void assertResult(int x, int y) { + Asserts.assertEQ((x + y) == 0, testIntAddtionEquals0(x, y)); + Asserts.assertEQ((x + y) != 0, testIntAddtionNotEquals0(x, y)); + Asserts.assertEQ((x | y) == 0, testIntOrEquals0(x, y)); + Asserts.assertEQ((x | y) != 0, testIntOrNotEquals0(x, y)); + Asserts.assertEQ((x | y) > 0, testIntOrGreater0(x, y)); + } + + @DontCompile + public void assertResult(long x, long y) { + Asserts.assertEQ((x + y) == 0, testLongAddtionEquals0(x, y)); + Asserts.assertEQ((x + y) != 0, testLongAddtionNotEquals0(x, y)); + Asserts.assertEQ((x | y) == 0, testLongOrEquals0(x, y)); + Asserts.assertEQ((x | y) != 0, testLongOrNotEquals0(x, y)); + Asserts.assertEQ((x | y) > 0, testLongOrGreater0(x, y)); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 3e2db1541dd..66dcc097d2c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2119,6 +2119,16 @@ public class IRNode { machOnlyNameRegex(X86_LOCK_XADDL, "xaddL"); } + public static final String X86_TESTI_REG = PREFIX + "X86_TESTI_REG" + POSTFIX; + static { + machOnlyNameRegex(X86_TESTI_REG, "testI_reg"); + } + + public static final String X86_TESTL_REG = PREFIX + "X86_TESTL_REG" + POSTFIX; + static { + machOnlyNameRegex(X86_TESTL_REG, "testL_reg"); + } + /* * Utility methods to set up IR_NODE_MAPPINGS. */ diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/TestRemovalPeephole.java b/test/micro/org/openjdk/bench/vm/compiler/x86/TestRemovalPeephole.java new file mode 100644 index 00000000000..415abca5a01 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/x86/TestRemovalPeephole.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023, 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. + */ +package org.openjdk.bench.vm.compiler.x86; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 2) +@Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) +@State(Scope.Thread) +public class TestRemovalPeephole { + long[] valuesLong1; + long[] valuesLong2; + int[] valuesInt1; + int[] valuesInt2; + long valueLong1; + long valueLong2; + int valueInt1; + int valueInt2; + + @Setup + public void setup() { + Random random = new Random(42); + valuesLong1 = new long[128]; + valuesLong2 = new long[128]; + for (int i = 0; i < valuesLong1.length; i++) { + valuesLong1[i] = random.nextLong(); + } + for (int i = 0; i < valuesLong2.length; i++) { + valuesLong2[i] = random.nextLong(); + } + + valuesInt1 = new int[128]; + valuesInt2 = new int[128]; + for (int i = 0; i < valuesInt1.length; i++) { + valuesInt1[i] = random.nextInt(); + } + for (int i = 0; i < valuesInt2.length; i++) { + valuesInt2[i] = random.nextInt(); + } + valueLong1 = random.nextLong(); + valueLong2 = random.nextLong(); + valueInt1 = random.nextInt(); + valueInt2 = random.nextInt(); + } + + @Benchmark + public void benchmarkAndTestFusableInt(Blackhole bh) { + for (int i = 0; i < valuesInt1.length; i++) { + int value1 = valuesInt1[i]; + int value2 = valuesInt2[i]; + int withAnd1 = value1 & 0xF; + int withAnd2 = value2 & 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + } + + @Benchmark + public void benchmarkAndTestFusableLong(Blackhole bh) { + for (int i = 0; i < valuesLong1.length; i++) { + long value1 = valuesLong1[i]; + long value2 = valuesLong2[i]; + long withAnd1 = value1 & 0xFFFFFFFFFFL; + long withAnd2 = value2 & 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + } + + @Benchmark + public void benchmarkOrTestFusableInt(Blackhole bh) { + for (int i = 0; i < valuesInt1.length; i++) { + int value1 = valuesInt1[i]; + int value2 = valuesInt2[i]; + int withAnd1 = value1 | 0xF; + int withAnd2 = value2 | 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + } + + @Benchmark + public void benchmarkOrTestFusableLong(Blackhole bh) { + for (int i = 0; i < valuesLong1.length; i++) { + long value1 = valuesLong1[i]; + long value2 = valuesLong2[i]; + long withAnd1 = value1 | 0xFFFFFFFFFFL; + long withAnd2 = value2 | 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + } + + @Benchmark + public void benchmarkXorTestFusableInt(Blackhole bh) { + for (int i = 0; i < valuesInt1.length; i++) { + int value1 = valuesInt1[i]; + int value2 = valuesInt2[i]; + int withAnd1 = value1 ^ 0xF; + int withAnd2 = value2 ^ 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + } + + @Benchmark + public void benchmarkXorTestFusableLong(Blackhole bh) { + for (int i = 0; i < valuesLong1.length; i++) { + long value1 = valuesLong1[i]; + long value2 = valuesLong2[i]; + long withAnd1 = value1 ^ 0xFFFFFFFFFFL; + long withAnd2 = value2 ^ 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + } + + + @Benchmark + public void benchmarkAndTestFusableIntSingle(Blackhole bh) { + int withAnd1 = valueInt1 & 0xF; + int withAnd2 = valueInt2 & 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + + @Benchmark + public void benchmarkAndTestFusableLongSingle(Blackhole bh) { + long withAnd1 = valueLong1 & 0xFFFFFFFFFFL; + long withAnd2 = valueLong2 & 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + + @Benchmark + public void benchmarkOrTestFusableIntSingle(Blackhole bh) { + int withAnd1 = valueInt1 | 0xF; + int withAnd2 = valueInt2 | 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + + @Benchmark + public void benchmarkOrTestFusableLongSingle(Blackhole bh) { + long withAnd1 = valueLong1 | 0xFFFFFFFFFFL; + long withAnd2 = valueLong2 | 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + + @Benchmark + public void benchmarkXorTestFusableIntSingle(Blackhole bh) { + int withAnd1 = valueInt1 ^ 0xF; + int withAnd2 = valueInt2 ^ 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + + @Benchmark + public void benchmarkXorTestFusableLongSingle(Blackhole bh) { + long withAnd1 = valueLong1 ^ 0xFFFFFFFFFFL; + long withAnd2 = valueLong2 ^ 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } +}