7017746: Regression : C2 compiler crash due to SIGSEGV in PhaseCFG::schedule_early()
Summary: Add TEMP edges (and KILL projections) before duplicated operands are removed in Expand() methods.
Reviewed-by: never
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Thu Feb 10 00:47:59 2011 -0800
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Thu Feb 10 14:25:59 2011 -0800
@@ -8125,6 +8125,17 @@
%}
#endif
+instruct cmpLTMask0( iRegI dst, iRegI src, immI0 zero, flagsReg ccr ) %{
+ match(Set dst (CmpLTMask src zero));
+ effect(KILL ccr);
+ size(4);
+ format %{ "SRA $src,#31,$dst\t# cmpLTMask0" %}
+ ins_encode %{
+ __ sra($src$$Register, 31, $dst$$Register);
+ %}
+ ins_pipe(ialu_reg_imm);
+%}
+
instruct cmpLTMask_reg_reg( iRegI dst, iRegI p, iRegI q, flagsReg ccr ) %{
match(Set dst (CmpLTMask p q));
effect( KILL ccr );
@@ -8144,19 +8155,7 @@
format %{ "SUBcc $p,$q,$p\t! p' = p-q\n\t"
"ADD $p,$y,$tmp\t! g3=p-q+y\n\t"
- "MOVl $tmp,$p\t! p' < 0 ? p'+y : p'" %}
- ins_encode( enc_cadd_cmpLTMask(p, q, y, tmp) );
- ins_pipe( cadd_cmpltmask );
-%}
-
-instruct cadd_cmpLTMask2( iRegI p, iRegI q, iRegI y, iRegI tmp, flagsReg ccr ) %{
- match(Set p (AddI (SubI p q) (AndI (CmpLTMask p q) y)));
- effect( KILL ccr, TEMP tmp);
- ins_cost(DEFAULT_COST*3);
-
- format %{ "SUBcc $p,$q,$p\t! p' = p-q\n\t"
- "ADD $p,$y,$tmp\t! g3=p-q+y\n\t"
- "MOVl $tmp,$p\t! p' < 0 ? p'+y : p'" %}
+ "MOVlt $tmp,$p\t! p' < 0 ? p'+y : p'" %}
ins_encode( enc_cadd_cmpLTMask(p, q, y, tmp) );
ins_pipe( cadd_cmpltmask );
%}
--- a/hotspot/src/share/vm/adlc/output_c.cpp Thu Feb 10 00:47:59 2011 -0800
+++ b/hotspot/src/share/vm/adlc/output_c.cpp Thu Feb 10 14:25:59 2011 -0800
@@ -1698,7 +1698,75 @@
fprintf(fp,"\n");
} // done generating expand rule
- else if( node->_matrule != NULL ) {
+ // Generate projections for instruction's additional DEFs and KILLs
+ if( ! node->expands() && (node->needs_projections() || node->has_temps())) {
+ // Get string representing the MachNode that projections point at
+ const char *machNode = "this";
+ // Generate the projections
+ fprintf(fp," // Add projection edges for additional defs or kills\n");
+
+ // Examine each component to see if it is a DEF or KILL
+ node->_components.reset();
+ // Skip the first component, if already handled as (SET dst (...))
+ Component *comp = NULL;
+ // For kills, the choice of projection numbers is arbitrary
+ int proj_no = 1;
+ bool declared_def = false;
+ bool declared_kill = false;
+
+ while( (comp = node->_components.iter()) != NULL ) {
+ // Lookup register class associated with operand type
+ Form *form = (Form*)_globalNames[comp->_type];
+ assert( form, "component type must be a defined form");
+ OperandForm *op = form->is_operand();
+
+ if (comp->is(Component::TEMP)) {
+ fprintf(fp, " // TEMP %s\n", comp->_name);
+ if (!declared_def) {
+ // Define the variable "def" to hold new MachProjNodes
+ fprintf(fp, " MachTempNode *def;\n");
+ declared_def = true;
+ }
+ if (op && op->_interface && op->_interface->is_RegInterface()) {
+ fprintf(fp," def = new (C) MachTempNode(state->MachOperGenerator( %s, C ));\n",
+ machOperEnum(op->_ident));
+ fprintf(fp," add_req(def);\n");
+ // The operand for TEMP is already constructed during
+ // this mach node construction, see buildMachNode().
+ //
+ // int idx = node->operand_position_format(comp->_name);
+ // fprintf(fp," set_opnd_array(%d, state->MachOperGenerator( %s, C ));\n",
+ // idx, machOperEnum(op->_ident));
+ } else {
+ assert(false, "can't have temps which aren't registers");
+ }
+ } else if (comp->isa(Component::KILL)) {
+ fprintf(fp, " // DEF/KILL %s\n", comp->_name);
+
+ if (!declared_kill) {
+ // Define the variable "kill" to hold new MachProjNodes
+ fprintf(fp, " MachProjNode *kill;\n");
+ declared_kill = true;
+ }
+
+ assert( op, "Support additional KILLS for base operands");
+ const char *regmask = reg_mask(*op);
+ const char *ideal_type = op->ideal_type(_globalNames, _register);
+
+ if (!op->is_bound_register()) {
+ syntax_err(node->_linenum, "In %s only bound registers can be killed: %s %s\n",
+ node->_ident, comp->_type, comp->_name);
+ }
+
+ fprintf(fp," kill = ");
+ fprintf(fp,"new (C, 1) MachProjNode( %s, %d, (%s), Op_%s );\n",
+ machNode, proj_no++, regmask, ideal_type);
+ fprintf(fp," proj_list.push(kill);\n");
+ }
+ }
+ }
+
+ if( !node->expands() && node->_matrule != NULL ) {
// Remove duplicated operands and inputs which use the same name.
// Seach through match operands for the same name usage.
uint cur_num_opnds = node->num_opnds();
@@ -1752,72 +1820,6 @@
}
}
-
- // Generate projections for instruction's additional DEFs and KILLs
- if( ! node->expands() && (node->needs_projections() || node->has_temps())) {
- // Get string representing the MachNode that projections point at
- const char *machNode = "this";
- // Generate the projections
- fprintf(fp," // Add projection edges for additional defs or kills\n");
-
- // Examine each component to see if it is a DEF or KILL
- node->_components.reset();
- // Skip the first component, if already handled as (SET dst (...))
- Component *comp = NULL;
- // For kills, the choice of projection numbers is arbitrary
- int proj_no = 1;
- bool declared_def = false;
- bool declared_kill = false;
-
- while( (comp = node->_components.iter()) != NULL ) {
- // Lookup register class associated with operand type
- Form *form = (Form*)_globalNames[comp->_type];
- assert( form, "component type must be a defined form");
- OperandForm *op = form->is_operand();
-
- if (comp->is(Component::TEMP)) {
- fprintf(fp, " // TEMP %s\n", comp->_name);
- if (!declared_def) {
- // Define the variable "def" to hold new MachProjNodes
- fprintf(fp, " MachTempNode *def;\n");
- declared_def = true;
- }
- if (op && op->_interface && op->_interface->is_RegInterface()) {
- fprintf(fp," def = new (C) MachTempNode(state->MachOperGenerator( %s, C ));\n",
- machOperEnum(op->_ident));
- fprintf(fp," add_req(def);\n");
- int idx = node->operand_position_format(comp->_name);
- fprintf(fp," set_opnd_array(%d, state->MachOperGenerator( %s, C ));\n",
- idx, machOperEnum(op->_ident));
- } else {
- assert(false, "can't have temps which aren't registers");
- }
- } else if (comp->isa(Component::KILL)) {
- fprintf(fp, " // DEF/KILL %s\n", comp->_name);
-
- if (!declared_kill) {
- // Define the variable "kill" to hold new MachProjNodes
- fprintf(fp, " MachProjNode *kill;\n");
- declared_kill = true;
- }
-
- assert( op, "Support additional KILLS for base operands");
- const char *regmask = reg_mask(*op);
- const char *ideal_type = op->ideal_type(_globalNames, _register);
-
- if (!op->is_bound_register()) {
- syntax_err(node->_linenum, "In %s only bound registers can be killed: %s %s\n",
- node->_ident, comp->_type, comp->_name);
- }
-
- fprintf(fp," kill = ");
- fprintf(fp,"new (C, 1) MachProjNode( %s, %d, (%s), Op_%s );\n",
- machNode, proj_no++, regmask, ideal_type);
- fprintf(fp," proj_list.push(kill);\n");
- }
- }
- }
-
// If the node is a MachConstantNode, insert the MachConstantBaseNode edge.
// NOTE: this edge must be the last input (see MachConstantNode::mach_constant_base_node_input).
if (node->is_mach_constant()) {
@@ -3776,12 +3778,10 @@
}
dont_care = true;
// For each operand not in the match rule, call MachOperGenerator
- // with the enum for the opcode that needs to be built
- // and the node just built, the parent of the operand.
+ // with the enum for the opcode that needs to be built.
ComponentList clist = inst->_components;
int index = clist.operand_position(comp->_name, comp->_usedef);
const char *opcode = machOperEnum(comp->_type);
- const char *parent = "node";
fprintf(fp_cpp, "%s node->set_opnd_array(%d, ", indent, index);
fprintf(fp_cpp, "MachOperGenerator(%s, C));\n", opcode);
}
--- a/hotspot/src/share/vm/opto/node.cpp Thu Feb 10 00:47:59 2011 -0800
+++ b/hotspot/src/share/vm/opto/node.cpp Thu Feb 10 14:25:59 2011 -0800
@@ -743,6 +743,9 @@
//------------------------------del_req----------------------------------------
// Delete the required edge and compact the edge array
void Node::del_req( uint idx ) {
+ assert( idx < _cnt, "oob");
+ assert( !VerifyHashTableKeys || _hash_lock == 0,
+ "remove node from hash table before modifying it");
// First remove corresponding def-use edge
Node *n = in(idx);
if (n != NULL) n->del_out((Node *)this);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/7017746/Test.java Thu Feb 10 14:25:59 2011 -0800
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+/**
+ * @test
+ * @bug 7017746
+ * @summary Regression : C2 compiler crash due to SIGSEGV in PhaseCFG::schedule_early()
+ *
+ * @run main/othervm -Xbatch Test
+ */
+
+public class Test {
+
+ int i;
+
+ static int test(Test t, int a, int b) {
+ int j = t.i;
+ int x = a - b;
+ if (a < b) x = x + j;
+ return x - j;
+ }
+
+ public static void main(String args[]) {
+ Test t = new Test();
+ for (int n = 0; n < 1000000; n++) {
+ int i = test(t, 1, 2);
+ }
+ }
+}
+