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