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.op.CoreOp; 26 import jdk.incubator.code.type.JavaType; 27 import java.util.HashMap; 28 import java.util.Set; 29 import java.util.function.BiConsumer; 30 import java.util.function.Predicate; 31 32 import static jdk.incubator.code.op.CoreOp.sub; 33 import static jdk.incubator.code.analysis.Patterns.*; 34 35 public final class ExpressionElimination { 36 private ExpressionElimination() { 37 } 38 39 static final JavaType J_L_MATH = JavaType.type(Math.class); 40 41 static OpPattern negP(Pattern operand) { 42 return opP(CoreOp.NegOp.class, operand); 43 } 44 45 static OpPattern addP(Pattern lhs, Pattern rhs) { 46 return opP(CoreOp.AddOp.class, lhs, rhs); 47 } 48 49 static OpPattern mulP(Pattern lhs, Pattern rhs) { 50 return opP(CoreOp.MulOp.class, lhs, rhs); 51 } 52 53 public static <T extends Op> T eliminate(T f) { 54 // Note expression elimination and other forms of analysis is simplified if first of all expressions 55 // are normalized e.g. when they have an operand that is a constant expression 56 // and the operation is associative such as add(0, x) -> add(x, 0) 57 58 var actions = multiMatch(new HashMap<Op.Result, BiConsumer<Block.Builder, Op>>(), f) 59 .pattern(mulP(_P(), valueP(constantP(0.0d)))) 60 .pattern(mulP(valueP(constantP(0.0d)), _P())) 61 .pattern(addP(valueP(), constantP(0.0d))) 62 .pattern(addP(constantP(0.0d), valueP())) 63 .pattern(mulP(constantP(1.0d), valueP())) 64 .pattern(mulP(valueP(), constantP(1.0d))) 65 .target((ms, as) -> { 66 Value a = ms.matchedOperands().get(0); 67 as.put(ms.op().result(), (block, op) -> { 68 CopyContext cc = block.context(); 69 cc.mapValue(ms.op().result(), cc.getValue(a)); 70 }); 71 return as; 72 }) 73 // add(neg(x), y) -> sub(y, x) 74 .pattern(addP(negP(valueP()), valueP())) 75 .target((ms, as) -> { 76 Value x = ms.matchedOperands().get(0); 77 Value y = ms.matchedOperands().get(1); 78 79 as.put(ms.op().result(), (block, op) -> { 80 CopyContext cc = block.context(); 81 Op.Result r = block.op(sub(cc.getValue(y), cc.getValue(x))); 82 cc.mapValue(ms.op().result(), r); 83 }); 84 return as; 85 }) 86 .matchThenApply(); 87 88 // Eliminate 89 Op ef = f.transform(CopyContext.create(), (block, op) -> { 90 BiConsumer<Block.Builder, Op> a = actions.get(op.result()); 91 if (a != null) { 92 a.accept(block, op); 93 } else { 94 block.op(op); 95 } 96 return block; 97 }); 98 99 Predicate<Op> testPure = op -> { 100 if (op instanceof Op.Pure) { 101 return true; 102 } else { 103 return op instanceof CoreOp.InvokeOp c && c.invokeDescriptor().refType().equals(J_L_MATH); 104 } 105 }; 106 107 while (true) { 108 Set<Op> unused = matchUnusedPureOps(ef, testPure); 109 if (unused.isEmpty()) { 110 break; 111 } 112 // Remove unused ops 113 ef = ef.transform(CopyContext.create(), (block, op) -> { 114 if (!unused.contains(op)) { 115 block.op(op); 116 } 117 return block; 118 }); 119 } 120 121 @SuppressWarnings("unchecked") 122 T t = (T) ef; 123 return t; 124 } 125 }