Skip to content

8381149: C2: postalloc: deduplicate vector constants#30500

Open
ruben-arm wants to merge 1 commit intoopenjdk:masterfrom
ruben-arm:pr-8381149
Open

8381149: C2: postalloc: deduplicate vector constants#30500
ruben-arm wants to merge 1 commit intoopenjdk:masterfrom
ruben-arm:pr-8381149

Conversation

@ruben-arm
Copy link
Copy Markdown
Contributor

@ruben-arm ruben-arm commented Mar 30, 2026

Some vector operations do not have inputs and essentially initialize vectors with a constant value. These operations can be marked for spilling and subsequently rematerialized at every use. The result of the transformation might look as follows:

   movi    v16.2d, #0x0
   str     q16, [x16, #64]
   movi    v16.2d, #0x0
   str     q16, [x16, #32]
   movi    v16.2d, #0x0
   str     q16, [x16, #16]
   movi    v16.2d, #0x0
   str     q16, [x16]
   movi    v16.2d, #0x0
   str     q16, [x16, #48]
   movi    v16.2d, #0x0
   str     q16, [x16, #112]
   movi    v16.2d, #0x0
   str     q16, [x16, #80]
   movi    v16.2d, #0x0
   str     q16, [x16, #96]

Introduce deduplication of these rematerialized vector constant initializations reducing the above sequence to:

   movi    v16.2d, #0x0
   str     q16, [x16, #64]
   str     q16, [x16, #32]
   str     q16, [x16, #16]
   str     q16, [x16]
   str     q16, [x16, #48]
   str     q16, [x16, #112]
   str     q16, [x16, #80]
   str     q16, [x16, #96]

Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Error

 ⚠️ Pull request body is missing required line: - [x] I confirm that I make this contribution in accordance with the [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai).

Issue

  • JDK-8381149: C2: postalloc: deduplicate vector constants (Enhancement - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/30500/head:pull/30500
$ git checkout pull/30500

Update a local copy of the PR:
$ git checkout pull/30500
$ git pull https://git.openjdk.org/jdk.git pull/30500/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 30500

View PR using the GUI difftool:
$ git pr show -t 30500

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/30500.diff

Using Webrev

Link to Webrev Comment

Some vector operations do not have inputs and essentially initialize
vectors with a constant value. These operations can be marked for
spilling and subsequently rematerialized at every use. The result of
the transformation might look as follows:
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#64]
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#32]
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#16]
   movi    v16.2d, #0x0
   str     q16, [x16]
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#48]
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#112]
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#80]
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#96]

Introduce deduplication of these rematerialized vector
constant initializations reducing the above sequence to:
   movi    v16.2d, #0x0
   str     q16, [x16, openjdk#64]
   str     q16, [x16, openjdk#32]
   str     q16, [x16, openjdk#16]
   str     q16, [x16]
   str     q16, [x16, openjdk#48]
   str     q16, [x16, openjdk#112]
   str     q16, [x16, openjdk#80]
   str     q16, [x16, openjdk#96]
@bridgekeeper
Copy link
Copy Markdown

bridgekeeper Bot commented Mar 30, 2026

👋 Welcome back ruben-arm! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link
Copy Markdown

openjdk Bot commented Mar 30, 2026

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk openjdk Bot added the hotspot-compiler hotspot-compiler-dev@openjdk.org label Mar 30, 2026
@openjdk
Copy link
Copy Markdown

openjdk Bot commented Mar 30, 2026

@ruben-arm The following label will be automatically applied to this pull request:

  • hotspot-compiler

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk Bot added the rfr Pull request is ready for review label Mar 30, 2026
@mlbridge
Copy link
Copy Markdown

mlbridge Bot commented Mar 30, 2026

Webrevs

@ruben-arm ruben-arm changed the title 8381149: C2: postaloc: deduplicate vector constants 8381149: C2: postalloc: deduplicate vector constants Mar 30, 2026
Comment on lines +2646 to +2787
// define_is_vector_same_const_value ------------------------------------------
void ArchDesc::buildVectorIsSameConstValue(FILE* fp) {
fprintf(fp, "bool Matcher::vector_is_same_const_value(const MachNode* node1, const MachNode* node2) {\n");
fprintf(fp, " assert(node1 != nullptr, \"node1 is unexpectedly nullptr\");\n");
fprintf(fp, " assert(node2 != nullptr, \"node2 is unexpectedly nullptr\");\n");
fprintf(fp, "\n");
fprintf(fp, " if (node1->rule() != node2->rule()) {\n");
fprintf(fp, " return false;\n");
fprintf(fp, " }\n");
fprintf(fp, "\n");
fprintf(fp, " assert(node1->num_opnds() == node2->num_opnds(),\n");
fprintf(fp, " \"the same rule, so the same number of operands\");\n");
fprintf(fp, "\n");
fprintf(fp, " const Type* node1_type = node1->bottom_type();\n");
fprintf(fp, " const Type* node2_type = node2->bottom_type();\n");
fprintf(fp, " if (node1_type != node2_type) {\n");
fprintf(fp, " return false;\n");
fprintf(fp, " }\n");
fprintf(fp, "\n");
fprintf(fp, " MachOper* opnd1, *opnd2;\n");
fprintf(fp, " switch ( node1->rule() ) {\n");

InstructForm* instr;
_instructions.reset();
while ( (instr = (InstructForm*)_instructions.iter()) != nullptr ) {
if ( instr->ideal_only() ) continue;
if ( !instr->sets_result() ) continue;
if ( !instr->is_vector() ) continue;

// At least one non-result operand
if ( instr->num_opnds() <= 1 ) continue;

bool all_operands_suitable = true;
Component* comp = nullptr;

instr->_components.reset();
while( (comp = instr->_components.iter()) != nullptr ) {
Form* form = (Form*)_globalNames[comp->_type];
assert(form != nullptr, "component type must be a defined form");
OperandForm* op = form->is_operand();

if ( op == nullptr ) {
// Not an OperandForm - conservatively reject.
all_operands_suitable = false;
break;
}

if ( comp->isa(Component::DEF) ) {
if ( comp->isa(Component::USE) ) {
// Result register is also an input.
all_operands_suitable = false;
break;
}

const char* result_type = op->ideal_type(_globalNames);

// Only consider operations writing to a vector operand.
if ( strncmp(result_type, "Vec", 3) != 0 ) {
all_operands_suitable = false;
break;
}

continue;
}

if ( op->_interface == nullptr ||
op->_interface->is_ConstInterface() == nullptr ||
op->num_edges(_globalNames) != 0) {
// Not a constant OperandForm.
all_operands_suitable = false;
break;
}

Form::DataType dtype = op->is_base_constant(_globalNames);
switch ( dtype ) {
case Form::idealH:
case Form::idealI:
case Form::idealL:
case Form::idealF:
case Form::idealD:
break;

default:
all_operands_suitable = false;
break;
}
}

if ( !all_operands_suitable ) continue;

fprintf(fp, " case %s_rule:\n", instr->_ident);
instr->_components.reset();
while( (comp = instr->_components.iter()) != nullptr ) {
if (comp->isa(Component::DEF)) continue;

Form* form = (Form*)_globalNames[comp->_type];
assert(form != nullptr, "component type must be a defined form");
OperandForm* op = form->is_operand();
assert(op != nullptr, "component type must be OperandForm");

Form::DataType dtype = op->is_base_constant(_globalNames);
const char* get_const = "";
const char* cast = "";
switch ( dtype ) {
case Form::idealH:
get_const = "constantH";
break;
case Form::idealI:
get_const = "constant";
break;
case Form::idealL:
get_const = "constantL";
break;
case Form::idealF:
get_const = "constantF";
cast = "jint_cast";
break;
case Form::idealD:
get_const = "constantD";
cast = "jlong_cast";
break;

default:
assert(false, "all other types should have been filtered out above.");
break;
}

int opnd_index = instr->operand_position(comp->_name, Component::USE);
fprintf(fp, " opnd1 = node1->_opnds[%d];\n", opnd_index);
fprintf(fp, " opnd2 = node2->_opnds[%d];\n", opnd_index);
fprintf(fp, " if (%s(opnd1->%s()) != %s(opnd2->%s())) return false;\n",
cast, get_const, cast, get_const);
}
fprintf(fp, " return true;\n");
}

fprintf(fp, " default:\n");
fprintf(fp, " return false;\n");
fprintf(fp, " }\n");
fprintf(fp, "}\n");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by comment: could you fix spacing here? E.g. if (cond), etc., and align cases with the switch

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the advice. I will adjust this in the next update.

Copy link
Copy Markdown
Contributor

@galderz galderz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Some minor comments.

} else if (old->is_Mach()) {
/* Same node is supplied twice so this is only to check if "old" is
* a initializer of a vector with a constant value */
return Matcher::vector_is_same_const_value(old->as_Mach(), old->as_Mach());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems odd to me.

Personally I would make 2 methods. One for here that answer the question "is vector constant initializer" and takes 1 argument, old->as_Mach(). And then keep a second method that takes 2 arguments and keeps the same name asking is the const value is the same. I think this would make things clearer and avoid the comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. I will change this into two methods in the next update.
Given this is for assertion purpose only, would it be suitable if the new method would be a proxy for the existing vector_is_same_const_value? (we could generate another method in the adlc but that might be more complexity than optimal in this case)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a proxy would be fine, but let's see if reviewers agree with this POV.

*/

public class TestPostAllocVectorConstDeduplication {
private static final VectorSpecies<Integer> I_SPECIES = IntVector.SPECIES_MAX;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Judging from the changes above that pattern match on different ideal... forms, should this be testing other types too? Long, float, double and float16?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I will extend the test in the next update.

Copy link
Copy Markdown
Contributor

@iwanowww iwanowww left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After studying proposed enhancement a bit, I'm curious why it is specific to vector constants. It looks like a peephole optimization opportunity for any repeated value rematerialization. (Unless when a constant value is encoded as an immediate maybe, but then register-based encoding can be more compact.)

@openjdk
Copy link
Copy Markdown

openjdk Bot commented Apr 16, 2026

The total number of required reviews for this PR has been set to 2 based on the presence of this label: hotspot-compiler. This can be overridden with the /reviewers command.

@openjdk openjdk Bot removed the rfr Pull request is ready for review label Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hotspot-compiler hotspot-compiler-dev@openjdk.org

Development

Successfully merging this pull request may close these issues.

4 participants