Jog
Pattern-Based Peephole Optimizations with Java JIT Tests
Install / Use
/learn @EngineeringSoftware/JogREADME
JOG
JOG is a framework that facilitates developing Java JIT peephole optimizations. JOG enables developers to write a pattern, in Java itself, that specifies desired code transformations by writing code before and after the optimization, as well as any necessary preconditions. Such patterns can be written in the same way that tests of the optimization are already written in OpenJDK. JOG translates each pattern into C/C++ code that can be integrated as a JIT optimization pass. JOG also generates Java tests for optimizations from patterns. Furthermore, JOG can automatically detect possible shadow relation between a pair of optimizations where the effect of the shadowed optimization is overridden by another.
Table of contents
Requirements
- Linux with GNU Bash (tested on Ubuntu 20.04 with GNU Bash 5.0.17(1)-release (x86_64-pc-linux-gnu))
- JDK >=11
We also provide a docker image with pre-built OpenJDK and cloned jog
repository.
docke pull zzqut/jog:latest
Example
Developers write Java JIT peephole optimizations in patterns, using
JOG's DSL fully embedded in Java. For example, Example.java contains
two patterns ADD2 and ADD7. ADD2 represents a peephole
optimization that transforms (a - b) + (c - d) to (a + c) - (b + d), and ADD7 expresses a peephole optimization that transforms
(a - b) + (b - c) to (a - c).
import jog.api.*;
import static jog.api.Action.*;
public class Example {
@Pattern
public void ADD2(long a, long b, long c, long d) {
before((a - b) + (c - d));
after((a + c) - (b + d));
}
@Pattern
public void ADD7(long a, long b, long c) {
before((a - b) + (b - c));
after(a - c);
}
}
From the patterns, JOG
-
Generates C/C++ code that can be integrated as JIT optimization pass.
JOG translates every pattern into corresponding optimization pass in C/C++.
gen-code/addnode.cpp/* Automatically generated by jog from patterns: ADD2, ADD7. */ Node* AddLNode::Ideal(PhaseGVN *phase, bool can_reshape) { // ADD2 { Node* _JOG_in1 = in(1); Node* _JOG_in11 = _JOG_in1 != NULL && 1 < _JOG_in1->req() ? _JOG_in1->in(1) : NULL; Node* _JOG_in12 = _JOG_in1 != NULL && 2 < _JOG_in1->req() ? _JOG_in1->in(2) : NULL; Node* _JOG_in2 = in(2); Node* _JOG_in21 = _JOG_in2 != NULL && 1 < _JOG_in2->req() ? _JOG_in2->in(1) : NULL; Node* _JOG_in22 = _JOG_in2 != NULL && 2 < _JOG_in2->req() ? _JOG_in2->in(2) : NULL; if (_JOG_in1->Opcode() == Op_SubL && _JOG_in2->Opcode() == Op_SubL) { return new SubLNode(phase->transform(new AddLNode(_JOG_in11, _JOG_in21)), phase->transform(new AddLNode(_JOG_in12, _JOG_in22))); } } // ADD7 { Node* _JOG_in1 = in(1); Node* _JOG_in11 = _JOG_in1 != NULL && 1 < _JOG_in1->req() ? _JOG_in1->in(1) : NULL; Node* _JOG_in12 = _JOG_in1 != NULL && 2 < _JOG_in1->req() ? _JOG_in1->in(2) : NULL; Node* _JOG_in2 = in(2); Node* _JOG_in21 = _JOG_in2 != NULL && 1 < _JOG_in2->req() ? _JOG_in2->in(1) : NULL; Node* _JOG_in22 = _JOG_in2 != NULL && 2 < _JOG_in2->req() ? _JOG_in2->in(2) : NULL; if (_JOG_in1->Opcode() == Op_SubL && _JOG_in2->Opcode() == Op_SubL && _JOG_in12 == _JOG_in21) { return new SubLNode(_JOG_in11, _JOG_in22); } } } -
Generates Java tests that can be used to test such optimizations.
The IR test, written in Java using IR test framework, is a recommended approach in OpenJDK to testing JIT peephole optimizations. JOG can automatically generate a IR test from every pattern.
gen-tests/TestAddLNode.java/*Automatically generated by jog from patterns: ADD2, ADD7.*/ package compiler.c2.irTests; import jdk.test.lib.Asserts; import compiler.lib.ir_framework.*; /*@test @library /test/lib / @run driver compiler.c2.irTests.TestAddLNode*/ public class TestAddLNode { public static void main(String[] args) { TestFramework.run(); } @Run(test = { "testADD2", "testADD7" }) public void runMethod() { long a = RunInfo.getRandom().nextLong(); long b = RunInfo.getRandom().nextLong(); long c = RunInfo.getRandom().nextLong(); long d = RunInfo.getRandom().nextLong(); long min = Long.MIN_VALUE; long max = Long.MAX_VALUE; assertResult(0, 0, 0, 0); assertResult(a, b, c, d); assertResult(min, min, min, min); assertResult(max, max, max, max); } @DontCompile public void assertResult(long a, long b, long c, long d) { Asserts.assertEQ((a - b) + (c - d), testADD2(a, b, c, d)); Asserts.assertEQ((a - b) + (b - c), testADD7(a, b, c)); } // Checks (a - b) + (c - d) => (a + c) - (b + d) @Test @IR(counts = { IRNode.ADD, "2", IRNode.SUB, "1" }) public long testADD2(long a, long b, long c, long d) { return (a - b) + (c - d); } // Checks (a - b) + (b - c) => a - c @Test @IR(failOn = { IRNode.ADD }) @IR(counts = { IRNode.SUB, "1" }) public long testADD7(long a, long b, long c) { return (a - b) + (b - c); } } -
Detects any possible shadow relation between a pair of optimizations.
Note that any expression matching
(a - b) + (c - a)(ADD2) also matches(a - b) + (b - c)(ADD7), which meansADD2can be applied whereverADD7can be applied, so the effect ofADD2will shadowADD7ifADD2is always applied beforeADD7in a compiler pass. JOG can automatically report the shadow relations.shadows.yml- shadowing: name: ADD2 before: "(a - b) + (c - d)" precondition: [] shadowed: - name: ADD7 before: "(a - b) + (b - c)" precondition: []
To run the example, please run ./demo.sh:
$ ./demo.sh
Building JOG...
Reading the patterns from file Example.java...
See gen-code/ for generated compiler pass in C/C++.
See gen-tests/ for generated JIT optimization tests in Java.
Shadow relations:
Pattern ADD2 shadows ADD7
Hall Of Fame
Here is the list of pull requests we opened for OpenJDK:
New optimizations:
-
#6441: 8277882: New subnode ideal optimization: converting "c0 - (x + c1)" into "(c0 - c1) - x".
-
#6675: 8278114: New addnode ideal optimization: converting "x + x" into "x << 1".
-
#6858: 8279607: Existing optimization "~x+1" -> "- x" can be generalized to "~x+c" -> "(c-1)-x".
-
#7795: 8283094: Add Ideal transformation: x + (con - y) -> (x - y) + con.
-
#7376: 8281453: New optimization: convert ~x into -1-x when ~x is used in an arithmetic expression.
-
#7395: 8281518: New optimization: convert "(x|y)-(x^y)" into "x&y".
-
#16333: Add Ideal transformation: (~a) & (~b) => ~(a | b)
-
#16334: Add Ideal transformation: (~a) | (~b) => ~(a & b)
New tests:
- #11049: 8297384: Add IR tests for existing idealizations of arithmetic nodes.
Fix detected shadowed optimizations:
- #6752: 8278471: Remove unreached rules in AddNode::IdealIL.
Citation
If you use JOG in your research, please cite our ISSTA'23 paper and ICSE'24 Demo paper.
@inproceedings{zang23jog,
author = {Zang, Zhiqiang and Thimmaiah, Aditya and Gligoric, Milos},
title = {Pattern-Based Peephole Optimizations with {J}ava {JIT} Tests},
booktitle = {International Symposium on Software Testing and Analysis},
pages = {64--75},
year= {2023},
doi = {10.1145/3597926.3598038},
}
@inproceedings{zang24jogtool,
title = {{JOG}: Java {JIT} Peephole Optimizations and Tests from Patterns},
author = {Zang, Zhiqiang and Thimmaiah, Aditya and Gligoric, Milos},
booktitle = {International Conference on Software Engineering, Tool Demonstrations Track},
pages = {to apear},
year= {2024},
doi = {10.1145/3639478.3640040}
}
Contact
Let me (Zhiqiang Zang) know if you have any questions.
Related Skills
node-connect
346.8kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
107.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
346.8kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
346.8kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
