aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm
diff options
context:
space:
mode:
authoriveresov <none@none>2014-03-12 11:24:26 -0700
committeriveresov <none@none>2014-03-12 11:24:26 -0700
commit1fb028c71167db3f4b8a9af4ae6c1fc4fc6ecc0a (patch)
tree34debf4cffbeb55dbb3bd60c67a3e17cba9e87ba /src/share/vm
parent2bbdf1d4cc262990989e64ace354e8428c81a002 (diff)
8031321: Support Intel bit manipulation instructions
Summary: Add support for BMI1 instructions Reviewed-by: kvn, roland
Diffstat (limited to 'src/share/vm')
-rw-r--r--src/share/vm/adlc/formssel.cpp12
-rw-r--r--src/share/vm/opto/matcher.cpp107
-rw-r--r--src/share/vm/opto/matcher.hpp3
3 files changed, 121 insertions, 1 deletions
diff --git a/src/share/vm/adlc/formssel.cpp b/src/share/vm/adlc/formssel.cpp
index 01aedd36a..b7cd6736e 100644
--- a/src/share/vm/adlc/formssel.cpp
+++ b/src/share/vm/adlc/formssel.cpp
@@ -649,6 +649,7 @@ int InstructForm::memory_operand(FormDict &globals) const {
int USE_of_memory = 0;
int DEF_of_memory = 0;
const char* last_memory_DEF = NULL; // to test DEF/USE pairing in asserts
+ const char* last_memory_USE = NULL;
Component *unique = NULL;
Component *comp = NULL;
ComponentList &components = (ComponentList &)_components;
@@ -670,7 +671,16 @@ int InstructForm::memory_operand(FormDict &globals) const {
assert(0 == strcmp(last_memory_DEF, comp->_name), "every memory DEF is followed by a USE of the same name");
last_memory_DEF = NULL;
}
- USE_of_memory++;
+ // Handles same memory being used multiple times in the case of BMI1 instructions.
+ if (last_memory_USE != NULL) {
+ if (strcmp(comp->_name, last_memory_USE) != 0) {
+ USE_of_memory++;
+ }
+ } else {
+ USE_of_memory++;
+ }
+ last_memory_USE = comp->_name;
+
if (DEF_of_memory == 0) // defs take precedence
unique = comp;
} else {
diff --git a/src/share/vm/opto/matcher.cpp b/src/share/vm/opto/matcher.cpp
index 5088deb7c..81e7455a8 100644
--- a/src/share/vm/opto/matcher.cpp
+++ b/src/share/vm/opto/matcher.cpp
@@ -1908,6 +1908,105 @@ OptoReg::Name Matcher::find_receiver( bool is_outgoing ) {
return OptoReg::as_OptoReg(regs.first());
}
+// This function identifies sub-graphs in which a 'load' node is
+// input to two different nodes, and such that it can be matched
+// with BMI instructions like blsi, blsr, etc.
+// Example : for b = -a[i] & a[i] can be matched to blsi r32, m32.
+// The graph is (AndL (SubL Con0 LoadL*) LoadL*), where LoadL*
+// refers to the same node.
+#ifdef X86
+// Match the generic fused operations pattern (op1 (op2 Con{ConType} mop) mop)
+// This is a temporary solution until we make DAGs expressible in ADL.
+template<typename ConType>
+class FusedPatternMatcher {
+ Node* _op1_node;
+ Node* _mop_node;
+ int _con_op;
+
+ static int match_next(Node* n, int next_op, int next_op_idx) {
+ if (n->in(1) == NULL || n->in(2) == NULL) {
+ return -1;
+ }
+
+ if (next_op_idx == -1) { // n is commutative, try rotations
+ if (n->in(1)->Opcode() == next_op) {
+ return 1;
+ } else if (n->in(2)->Opcode() == next_op) {
+ return 2;
+ }
+ } else {
+ assert(next_op_idx > 0 && next_op_idx <= 2, "Bad argument index");
+ if (n->in(next_op_idx)->Opcode() == next_op) {
+ return next_op_idx;
+ }
+ }
+ return -1;
+ }
+public:
+ FusedPatternMatcher(Node* op1_node, Node *mop_node, int con_op) :
+ _op1_node(op1_node), _mop_node(mop_node), _con_op(con_op) { }
+
+ bool match(int op1, int op1_op2_idx, // op1 and the index of the op1->op2 edge, -1 if op1 is commutative
+ int op2, int op2_con_idx, // op2 and the index of the op2->con edge, -1 if op2 is commutative
+ typename ConType::NativeType con_value) {
+ if (_op1_node->Opcode() != op1) {
+ return false;
+ }
+ if (_mop_node->outcnt() > 2) {
+ return false;
+ }
+ op1_op2_idx = match_next(_op1_node, op2, op1_op2_idx);
+ if (op1_op2_idx == -1) {
+ return false;
+ }
+ // Memory operation must be the other edge
+ int op1_mop_idx = (op1_op2_idx & 1) + 1;
+
+ // Check that the mop node is really what we want
+ if (_op1_node->in(op1_mop_idx) == _mop_node) {
+ Node *op2_node = _op1_node->in(op1_op2_idx);
+ if (op2_node->outcnt() > 1) {
+ return false;
+ }
+ assert(op2_node->Opcode() == op2, "Should be");
+ op2_con_idx = match_next(op2_node, _con_op, op2_con_idx);
+ if (op2_con_idx == -1) {
+ return false;
+ }
+ // Memory operation must be the other edge
+ int op2_mop_idx = (op2_con_idx & 1) + 1;
+ // Check that the memory operation is the same node
+ if (op2_node->in(op2_mop_idx) == _mop_node) {
+ // Now check the constant
+ const Type* con_type = op2_node->in(op2_con_idx)->bottom_type();
+ if (con_type != Type::TOP && ConType::as_self(con_type)->get_con() == con_value) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+};
+
+
+bool Matcher::is_bmi_pattern(Node *n, Node *m) {
+ if (n != NULL && m != NULL) {
+ if (m->Opcode() == Op_LoadI) {
+ FusedPatternMatcher<TypeInt> bmii(n, m, Op_ConI);
+ return bmii.match(Op_AndI, -1, Op_SubI, 1, 0) ||
+ bmii.match(Op_AndI, -1, Op_AddI, -1, -1) ||
+ bmii.match(Op_XorI, -1, Op_AddI, -1, -1);
+ } else if (m->Opcode() == Op_LoadL) {
+ FusedPatternMatcher<TypeLong> bmil(n, m, Op_ConL);
+ return bmil.match(Op_AndL, -1, Op_SubL, 1, 0) ||
+ bmil.match(Op_AndL, -1, Op_AddL, -1, -1) ||
+ bmil.match(Op_XorL, -1, Op_AddL, -1, -1);
+ }
+ }
+ return false;
+}
+#endif // X86
+
// A method-klass-holder may be passed in the inline_cache_reg
// and then expanded into the inline_cache_reg and a method_oop register
// defined in ad_<arch>.cpp
@@ -2063,6 +2162,14 @@ void Matcher::find_shared( Node *n ) {
set_shared(m->in(AddPNode::Base)->in(1));
}
+ // if 'n' and 'm' are part of a graph for BMI instruction, clone this node.
+#ifdef X86
+ if (UseBMI1Instructions && is_bmi_pattern(n, m)) {
+ mstack.push(m, Visit);
+ continue;
+ }
+#endif
+
// Clone addressing expressions as they are "free" in memory access instructions
if( mem_op && i == MemNode::Address && mop == Op_AddP ) {
// Some inputs for address expression are not put on stack
diff --git a/src/share/vm/opto/matcher.hpp b/src/share/vm/opto/matcher.hpp
index 5ebf59068..6d90b9fb7 100644
--- a/src/share/vm/opto/matcher.hpp
+++ b/src/share/vm/opto/matcher.hpp
@@ -79,6 +79,9 @@ class Matcher : public PhaseTransform {
// Find shared Nodes, or Nodes that otherwise are Matcher roots
void find_shared( Node *n );
+#ifdef X86
+ bool is_bmi_pattern(Node *n, Node *m);
+#endif
// Debug and profile information for nodes in old space:
GrowableArray<Node_Notes*>* _old_node_note_array;