1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 import jdk.incubator.code.*;
25 import jdk.incubator.code.dialect.java.JavaOp;
26
27 import java.util.HashMap;
28 import java.util.function.BiConsumer;
29
30 import static jdk.incubator.code.dialect.java.JavaOp.sub;
31 import static jdk.incubator.code.analysis.Patterns.*;
32
33 public final class ExpressionElimination {
34 private ExpressionElimination() {
35 }
36
37 static OpPattern negP(Pattern operand) {
38 return opP(JavaOp.NegOp.class, operand);
39 }
40
41 static OpPattern addP(Pattern lhs, Pattern rhs) {
42 return opP(JavaOp.AddOp.class, lhs, rhs);
43 }
44
45 static OpPattern mulP(Pattern lhs, Pattern rhs) {
46 return opP(JavaOp.MulOp.class, lhs, rhs);
47 }
48
49 public static <T extends Op> T eliminate(T f) {
50 // Note expression elimination and other forms of analysis is simplified if first of all expressions
51 // are normalized e.g. when they have an operand that is a constant expression
52 // and the operation is associative such as add(0, x) -> add(x, 0)
53
54 var actions = multiMatch(new HashMap<Op.Result, BiConsumer<Block.Builder, Op>>(), f)
55 .pattern(mulP(_P(), valueP(constantP(0.0d))))
56 .pattern(mulP(valueP(constantP(0.0d)), _P()))
57 .pattern(addP(valueP(), constantP(0.0d)))
58 .pattern(addP(constantP(0.0d), valueP()))
59 .pattern(mulP(constantP(1.0d), valueP()))
60 .pattern(mulP(valueP(), constantP(1.0d)))
61 .target((ms, as) -> {
62 Value a = ms.matchedOperands().get(0);
63 as.put(ms.op().result(), (block, op) -> {
64 CopyContext cc = block.context();
65 cc.mapValue(ms.op().result(), cc.getValue(a));
66 });
67 return as;
68 })
69 // add(neg(x), y) -> sub(y, x)
70 .pattern(addP(negP(valueP()), valueP()))
71 .target((ms, as) -> {
72 Value x = ms.matchedOperands().get(0);
73 Value y = ms.matchedOperands().get(1);
74
75 as.put(ms.op().result(), (block, op) -> {
76 CopyContext cc = block.context();
77 Op.Result r = block.op(sub(cc.getValue(y), cc.getValue(x)));
78 cc.mapValue(ms.op().result(), r);
79 });
80 return as;
81 })
82 .matchThenApply();
83
84 // Eliminate
85 Op ef = f.transform(CopyContext.create(), (block, op) -> {
86 BiConsumer<Block.Builder, Op> a = actions.get(op.result());
87 if (a != null) {
88 a.accept(block, op);
89 } else {
90 block.op(op);
91 }
92 return block;
93 });
94
95 // Remove dead ops
96 ef = ef.transform(CopyContext.create(), (block, op) -> {
97 if (!(op instanceof Op.Pure) ||
98 !op.result().uses().isEmpty()) {
99 block.op(op);
100 }
101 return block;
102 });
103
104 @SuppressWarnings("unchecked")
105 T t = (T) ef;
106 return t;
107 }
108 }