64 /*
65 * @test id=StoreNSerial
66 * @bug 8020282
67 * @summary Test that we do not generate redundant leas on x86 when storing narrow oops to object arrays.
68 * @requires os.simpleArch == "x64" & vm.gc.Serial
69 * @modules jdk.compiler/com.sun.tools.javac.util
70 * @library /test/lib /
71 * @run driver compiler.codegen.TestRedundantLea StoreNSerial
72 */
73
74 /*
75 * @test id=StoreNParallel
76 * @bug 8020282
77 * @summary Test that we do not generate redundant leas on x86 when storing narrow oops to object arrays.
78 * @requires os.simpleArch == "x64" & vm.gc.Parallel
79 * @modules jdk.compiler/com.sun.tools.javac.util
80 * @library /test/lib /
81 * @run driver compiler.codegen.TestRedundantLea StoreNParallel
82 */
83
84
85 package compiler.codegen;
86
87 import java.util.concurrent.atomic.*;
88 import java.util.regex.Matcher;
89 import java.util.regex.Pattern;
90
91 import com.sun.tools.javac.util.*;
92
93 import compiler.lib.ir_framework.*;
94
95 // The following tests ensure that we do not generate a redundant lea instruction on x86.
96 // These get generated on chained dereferences for the rules leaPCompressedOopOffset,
97 // leaP8Narrow, and leaP32Narrow and stem from a decodeHeapOopNotNull that is not needed
98 // unless the derived oop is added to an oop map. The redundant lea is removed with an
99 // opto assembly peephole optimization. Hence, all tests below feature a negative test
100 // run with -XX:-OptoPeephole to detect changes that obsolete that peephole.
101 // Further, all tests are run with different max heap sizes to trigger the generation of
102 // different lea match rules: -XX:MaxHeapSize=32m generates leaP(8|32)Narrow and
103 // -XX:MaxHeapSize=4g generates leaPCompressedOopOffset, since the address computation
112 }
113 case "StringEquals" -> {
114 framework = new TestFramework(StringEqualsTest.class);
115 framework.addHelperClasses(StringEqualsTestHelper.class);
116 }
117 case "StringInflate" -> {
118 framework = new TestFramework(StringInflateTest.class);
119 framework.addFlags("--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED");
120 }
121 case "RegexFind" -> {
122 framework = new TestFramework(RegexFindTest.class);
123 }
124 case "StoreNSerial" -> {
125 framework = new TestFramework(StoreNTest.class);
126 framework.addFlags("-XX:+UseSerialGC");
127 }
128 case "StoreNParallel" -> {
129 framework = new TestFramework(StoreNTest.class);
130 framework.addFlags("-XX:+UseParallelGC");
131 }
132 default -> {
133 throw new IllegalArgumentException("Unknown test name \"" + testName +"\"");
134 }
135 }
136
137 Scenario[] scenarios = new Scenario[2];
138 // Scenario for the negative test without peephole optimizations.
139 scenarios[0] = new Scenario(0, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-OptoPeephole");
140 // Scenario for the positive test with +OptoPeephole (the default on x64).
141 scenarios[1] = new Scenario(1);
142 framework.addScenarios(scenarios).start();
143 }
144 }
145
146 // This generates a leaP* rule for the chained dereference of obj.value that
147 // gets passed to the get and set VM intrinsic.
148 class GetAndSetTest {
149 private static final Object CURRENT = new Object();
150 private final AtomicReference<Object> obj = new AtomicReference<Object>();
151
257 @IR(counts = {IRNode.LEA_P, "=1"},
258 phase = {CompilePhase.FINAL_CODE},
259 applyIfPlatform = {"mac", "false"})
260 // Due to unpredictable code generation, we cannot match the exact number of decodes below.
261 // Negative test
262 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, ">=7"},
263 phase = {CompilePhase.FINAL_CODE},
264 applyIfAnd = {"OptoPeephole", "false", "UseAVX", "=3"})
265 // Test that the peephole worked for leaPCompressedOopOffset
266 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, ">=6"},
267 phase = {CompilePhase.FINAL_CODE},
268 applyIfAnd = {"OptoPeephole", "true", "UseAVX", "=3"})
269 @Arguments(setup = "setup")
270 public boolean test(Matcher m) {
271 return m.find();
272 }
273 }
274
275 // The matcher generates leaP* rules for storing an object in an array of objects
276 // at a constant offset, but only when using the Serial or Parallel GC.
277 // Here, we can also manipulate the offset such that we get a leaP32Narrow rule
278 // and we can demonstrate that the peephole also removes simple cases of unneeded
279 // spills.
280 class StoreNTest {
281 private static final int SOME_SIZE = 42;
282 private static final int OFFSET8BIT_IDX = 3;
283 private static final int OFFSET32BIT_IDX = 33;
284
285 private static final Object CURRENT = new Object();
286 private static final Object OTHER = new Object();
287
288 private StoreNTestHelper[] classArr8bit = new StoreNTestHelper[SOME_SIZE];
289 private StoreNTestHelper[] classArr32bit = new StoreNTestHelper[SOME_SIZE];
290 private Object[] objArr8bit = new Object[SOME_SIZE];
291 private Object[] objArr32bit = new Object[SOME_SIZE];
292
293 @Test
294 @IR(counts = {IRNode.LEA_P, "=2"},
295 phase = {CompilePhase.FINAL_CODE},
296 applyIfPlatform = {"mac", "false"})
297 // Negative test
298 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=2"},
299 phase = {CompilePhase.FINAL_CODE},
300 applyIf = {"OptoPeephole", "false"})
301 // Test that the peephole worked for leaPCompressedOopOffset
302 @IR(failOn = {IRNode.DECODE_HEAP_OOP_NOT_NULL},
303 phase = {CompilePhase.FINAL_CODE},
304 applyIf = {"OptoPeephole", "true"})
305 // Test that the peephole removes a spill.
306 @IR(counts = {IRNode.MEM_TO_REG_SPILL_COPY, "=4"},
307 phase = {CompilePhase.FINAL_CODE},
308 applyIfAnd ={"OptoPeephole", "false", "UseCompactObjectHeaders", "false"})
309 @IR(counts = {IRNode.MEM_TO_REG_SPILL_COPY, "=3"},
310 phase = {CompilePhase.FINAL_CODE},
311 applyIfAnd ={"OptoPeephole", "true", "UseCompactObjectHeaders", "false"})
312 public void testRemoveSpill() {
313 this.classArr8bit[OFFSET8BIT_IDX] = new StoreNTestHelper(CURRENT, OTHER);
314 this.classArr32bit[OFFSET32BIT_IDX] = new StoreNTestHelper(OTHER, CURRENT);
315 }
316
317 // This variation of the test above generates a split spill register path.
318 // Due to the complicated graph structure with the phis, the peephole
319 // cannot remove the redundant decode shared by both leaP*s.
320 @Test
321 @IR(counts = {IRNode.LEA_P, "=2"},
322 phase = {CompilePhase.FINAL_CODE},
323 applyIfPlatform = {"mac", "false"})
324 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=1"},
325 phase = {CompilePhase.FINAL_CODE},
326 applyIf = {"OptoPeephole", "false"})
327 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=1"},
328 phase = {CompilePhase.FINAL_CODE},
329 applyIf = {"OptoPeephole", "true"})
330 public void testPhiSpill() {
331 this.classArr8bit[OFFSET8BIT_IDX] = new StoreNTestHelper(CURRENT, OTHER);
332 this.classArr8bit[OFFSET32BIT_IDX] = new StoreNTestHelper(CURRENT, OTHER);
333 }
334
335 @Test
336 @IR(counts = {IRNode.LEA_P, "=2"},
337 phase = {CompilePhase.FINAL_CODE},
338 applyIfPlatform = {"mac", "false"})
339 // Negative test
340 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=2"},
341 phase = {CompilePhase.FINAL_CODE},
342 applyIf = {"OptoPeephole", "false"})
343 // Test that the peephole worked for leaPCompressedOopOffset
344 @IR(failOn = {IRNode.DECODE_HEAP_OOP_NOT_NULL},
345 phase = {CompilePhase.FINAL_CODE},
346 applyIf = {"OptoPeephole", "true"})
347 public void testNoAlloc() {
348 this.objArr8bit[OFFSET8BIT_IDX] = CURRENT;
349 this.objArr32bit[OFFSET32BIT_IDX] = OTHER;
350 }
351
352 @Test
353 @IR(counts = {IRNode.LEA_P, "=2"},
354 phase = {CompilePhase.FINAL_CODE},
355 applyIfPlatform = {"mac", "false"})
356 // Negative test
357 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=1"},
358 phase = {CompilePhase.FINAL_CODE},
359 applyIf = {"OptoPeephole", "false"})
360 // Test that the peephole worked for leaPCompressedOopOffset
361 @IR(failOn = {IRNode.DECODE_HEAP_OOP_NOT_NULL},
362 phase = {CompilePhase.FINAL_CODE},
363 applyIf = {"OptoPeephole", "true"})
364 public void testNoAllocSameArray() {
365 this.objArr8bit[OFFSET8BIT_IDX] = CURRENT;
366 this.objArr8bit[OFFSET32BIT_IDX] = OTHER;
367 }
368 }
369
370 class StoreNTestHelper {
371 Object o1;
372 Object o2;
373
374 public StoreNTestHelper(Object o1, Object o2) {
375 this.o1 = o1;
376 this.o2 = o2;
377 }
378 }
|
64 /*
65 * @test id=StoreNSerial
66 * @bug 8020282
67 * @summary Test that we do not generate redundant leas on x86 when storing narrow oops to object arrays.
68 * @requires os.simpleArch == "x64" & vm.gc.Serial
69 * @modules jdk.compiler/com.sun.tools.javac.util
70 * @library /test/lib /
71 * @run driver compiler.codegen.TestRedundantLea StoreNSerial
72 */
73
74 /*
75 * @test id=StoreNParallel
76 * @bug 8020282
77 * @summary Test that we do not generate redundant leas on x86 when storing narrow oops to object arrays.
78 * @requires os.simpleArch == "x64" & vm.gc.Parallel
79 * @modules jdk.compiler/com.sun.tools.javac.util
80 * @library /test/lib /
81 * @run driver compiler.codegen.TestRedundantLea StoreNParallel
82 */
83
84 /*
85 * @test id=Spill
86 * @bug 8020282
87 * @summary Test that we do not generate redundant leas and remove related spills on x86.
88 * @requires os.simpleArch == "x64"
89 * @modules jdk.compiler/com.sun.tools.javac.util
90 * @library /test/lib /
91 * @run driver compiler.codegen.TestRedundantLea Spill
92 */
93
94
95 package compiler.codegen;
96
97 import java.util.concurrent.atomic.*;
98 import java.util.regex.Matcher;
99 import java.util.regex.Pattern;
100
101 import com.sun.tools.javac.util.*;
102
103 import compiler.lib.ir_framework.*;
104
105 // The following tests ensure that we do not generate a redundant lea instruction on x86.
106 // These get generated on chained dereferences for the rules leaPCompressedOopOffset,
107 // leaP8Narrow, and leaP32Narrow and stem from a decodeHeapOopNotNull that is not needed
108 // unless the derived oop is added to an oop map. The redundant lea is removed with an
109 // opto assembly peephole optimization. Hence, all tests below feature a negative test
110 // run with -XX:-OptoPeephole to detect changes that obsolete that peephole.
111 // Further, all tests are run with different max heap sizes to trigger the generation of
112 // different lea match rules: -XX:MaxHeapSize=32m generates leaP(8|32)Narrow and
113 // -XX:MaxHeapSize=4g generates leaPCompressedOopOffset, since the address computation
122 }
123 case "StringEquals" -> {
124 framework = new TestFramework(StringEqualsTest.class);
125 framework.addHelperClasses(StringEqualsTestHelper.class);
126 }
127 case "StringInflate" -> {
128 framework = new TestFramework(StringInflateTest.class);
129 framework.addFlags("--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED");
130 }
131 case "RegexFind" -> {
132 framework = new TestFramework(RegexFindTest.class);
133 }
134 case "StoreNSerial" -> {
135 framework = new TestFramework(StoreNTest.class);
136 framework.addFlags("-XX:+UseSerialGC");
137 }
138 case "StoreNParallel" -> {
139 framework = new TestFramework(StoreNTest.class);
140 framework.addFlags("-XX:+UseParallelGC");
141 }
142 case "Spill" -> {
143 framework = new TestFramework(SpillTest.class);
144 }
145 default -> {
146 throw new IllegalArgumentException("Unknown test name \"" + testName +"\"");
147 }
148 }
149
150 Scenario[] scenarios = new Scenario[2];
151 // Scenario for the negative test without peephole optimizations.
152 scenarios[0] = new Scenario(0, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-OptoPeephole");
153 // Scenario for the positive test with +OptoPeephole (the default on x64).
154 scenarios[1] = new Scenario(1);
155 framework.addScenarios(scenarios).start();
156 }
157 }
158
159 // This generates a leaP* rule for the chained dereference of obj.value that
160 // gets passed to the get and set VM intrinsic.
161 class GetAndSetTest {
162 private static final Object CURRENT = new Object();
163 private final AtomicReference<Object> obj = new AtomicReference<Object>();
164
270 @IR(counts = {IRNode.LEA_P, "=1"},
271 phase = {CompilePhase.FINAL_CODE},
272 applyIfPlatform = {"mac", "false"})
273 // Due to unpredictable code generation, we cannot match the exact number of decodes below.
274 // Negative test
275 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, ">=7"},
276 phase = {CompilePhase.FINAL_CODE},
277 applyIfAnd = {"OptoPeephole", "false", "UseAVX", "=3"})
278 // Test that the peephole worked for leaPCompressedOopOffset
279 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, ">=6"},
280 phase = {CompilePhase.FINAL_CODE},
281 applyIfAnd = {"OptoPeephole", "true", "UseAVX", "=3"})
282 @Arguments(setup = "setup")
283 public boolean test(Matcher m) {
284 return m.find();
285 }
286 }
287
288 // The matcher generates leaP* rules for storing an object in an array of objects
289 // at a constant offset, but only when using the Serial or Parallel GC.
290 // Here, we can also manipulate the offset such that we get a leaP32Narrow rule.
291 class StoreNTest {
292 private static final int SOME_SIZE = 42;
293 private static final int OFFSET8BIT_IDX = 3;
294 private static final int OFFSET32BIT_IDX = 33;
295
296 private static final Object CURRENT = new Object();
297 private static final Object OTHER = new Object();
298
299 private StoreNTestHelper[] classArr8bit = new StoreNTestHelper[SOME_SIZE];
300 private StoreNTestHelper[] classArr32bit = new StoreNTestHelper[SOME_SIZE];
301
302 @Test
303 @IR(counts = {IRNode.LEA_P, "=2"},
304 phase = {CompilePhase.FINAL_CODE},
305 applyIfPlatform = {"mac", "false"})
306 // Negative test
307 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=2"},
308 phase = {CompilePhase.FINAL_CODE},
309 applyIf = {"OptoPeephole", "false"})
310 // Test that the peephole worked for leaPCompressedOopOffset
311 @IR(failOn = {IRNode.DECODE_HEAP_OOP_NOT_NULL},
312 phase = {CompilePhase.FINAL_CODE},
313 applyIf = {"OptoPeephole", "true"})
314 public void testRemoveSpill() {
315 this.classArr8bit[OFFSET8BIT_IDX] = new StoreNTestHelper(CURRENT, OTHER);
316 this.classArr32bit[OFFSET32BIT_IDX] = new StoreNTestHelper(OTHER, CURRENT);
317 }
318
319 // This variation of the test above generates a split spill register path.
320 // Due to the complicated graph structure with the phis, the peephole
321 // cannot remove the redundant decode shared by both leaP*s.
322 @Test
323 @IR(counts = {IRNode.LEA_P, "=2"},
324 phase = {CompilePhase.FINAL_CODE},
325 applyIfPlatform = {"mac", "false"})
326 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=1"},
327 phase = {CompilePhase.FINAL_CODE},
328 applyIf = {"OptoPeephole", "false"})
329 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "=1"},
330 phase = {CompilePhase.FINAL_CODE},
331 applyIf = {"OptoPeephole", "true"})
332 public void testPhiSpill() {
333 this.classArr8bit[OFFSET8BIT_IDX] = new StoreNTestHelper(CURRENT, OTHER);
334 this.classArr8bit[OFFSET32BIT_IDX] = new StoreNTestHelper(CURRENT, OTHER);
335 }
336 }
337
338 class StoreNTestHelper {
339 Object o1;
340 Object o2;
341
342 public StoreNTestHelper(Object o1, Object o2) {
343 this.o1 = o1;
344 this.o2 = o2;
345 }
346 }
347
348 // This test validates that the peephole removes simple spills.
349 // The code for the test originates from compiler/escapeAnalysis/Test6775880.java.
350 class SpillTest {
351 int cnt;
352 int b[];
353 String s;
354
355 @Run(test = "test")
356 public static void run() {
357 SpillTest t = new SpillTest();
358 t.cnt = 3;
359 t.b = new int[3];
360 t.b[0] = 0;
361 t.b[1] = 1;
362 t.b[2] = 2;
363 int j = 0;
364 t.s = "";
365 t.test();
366 }
367
368 @Test
369 // TODO: Make tests more precise
370 @IR(counts = {IRNode.LEA_P, "=2"},
371 phase = {CompilePhase.FINAL_CODE},
372 applyIfPlatform = {"mac", "false"})
373 // Negative test
374 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, ">=2"},
375 phase = {CompilePhase.FINAL_CODE},
376 applyIf = {"OptoPeephole", "false"})
377 @IR(counts = {IRNode.DECODE_HEAP_OOP_NOT_NULL, "<=2"},
378 phase = {CompilePhase.FINAL_CODE},
379 applyIf = {"OptoPeephole", "true"})
380 // Test that the peephole removes a spill.
381 @IR(counts = {IRNode.MEM_TO_REG_SPILL_COPY, ">=18"},
382 phase = {CompilePhase.FINAL_CODE},
383 applyIf = {"OptoPeephole", "false"})
384 @IR(counts = {IRNode.MEM_TO_REG_SPILL_COPY, ">=16"},
385 phase = {CompilePhase.FINAL_CODE},
386 applyIf = {"OptoPeephole", "true"})
387 String test() {
388 String res = "";
389 for (int i = 0; i < cnt; i++) {
390 if (i != 0) {
391 res = res + ".";
392 }
393 res = res + b[i];
394 }
395 return res;
396 }
397 }
|