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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.code; 27 28 import java.util.List; 29 import java.util.function.BiFunction; 30 31 /** 32 * An operation transformer. 33 */ 34 @FunctionalInterface 35 // @@@ Change to OpTransform or CodeTransform 36 public interface OpTransformer { 37 38 /** 39 * A copying transformer that applies the operation to the block builder, and returning the block builder. 40 */ 41 OpTransformer COPYING_TRANSFORMER = (block, op) -> { 42 block.op(op); 43 return block; 44 }; 45 46 /** 47 * A transformer that drops location information from operations. 48 */ 49 OpTransformer DROP_LOCATION_TRANSFORMER = (block, op) -> { 50 Op.Result r = block.op(op); 51 r.op().setLocation(Location.NO_LOCATION); 52 return block; 53 }; 54 55 /** 56 * A transformer that lowers operations that are {@link Op.Lowerable lowerable}, 57 * and copies other operations. 58 */ 59 OpTransformer LOWERING_TRANSFORMER = (block, op) -> { 60 if (op instanceof Op.Lowerable lop) { 61 return lop.lower(block, null); 62 } else { 63 block.op(op); 64 return block; 65 } 66 }; 67 68 /** 69 * Transforms a body starting from a block builder. 70 * 71 * @implSpec 72 * The default implementation {@link #acceptBlock(Block.Builder, Block) accepts} a block builder 73 * and a block for each block of the body, in order, using this operation transformer. 74 * The following sequence of actions is performed: 75 * <ol> 76 * <li> 77 * the body's entry block is mapped to the block builder, and the (input) block parameters of the 78 * body's entry block are mapped to the (output) values, using the builder's context. 79 * <li>for each (input) block in the body (except the entry block) an (output) block builder is created 80 * from the builder with the same parameter types as the (input) block, in order. 81 * The (input) block is mapped to the (output) builder, and the (input) block parameters are mapped to the 82 * (output) block parameters, using the builder's context. 83 * <li> 84 * for each (input) block in the body (in order) the (input) block is transformed 85 * by {@link #acceptBlock(Block.Builder, Block) accepting} the mapped (output) builder and 86 * (input) block, using this operation transformer. 87 * </ol> 88 * 89 * @param builder the block builder 90 * @param body the body to transform 91 * @param values the values to map to the body's entry block parameters 92 */ 93 default void acceptBody(Block.Builder builder, Body body, List<? extends Value> values) { 94 CopyContext cc = builder.context(); 95 96 // Map blocks up front, for forward referencing successors 97 for (Block block : body.blocks()) { 98 if (block.isEntryBlock()) { 99 cc.mapBlock(block, builder); 100 cc.mapValues(block.parameters(), values); 101 } else { 102 Block.Builder blockBuilder = builder.block(block.parameterTypes()); 103 cc.mapBlock(block, blockBuilder); 104 cc.mapValues(block.parameters(), blockBuilder.parameters()); 105 } 106 } 107 108 // Transform blocks 109 for (Block b : body.blocks()) { 110 acceptBlock(cc.getBlock(b), b); 111 } 112 } 113 114 /** 115 * Transforms a block starting from a block builder. 116 * 117 * @implSpec 118 * The default implementation {@link #acceptOp(Block.Builder, Op) accepts} a block builder 119 * and an operation for each operation of the block, in order, using this operation transformer. 120 * On first iteration the block builder that is applied is block builder passed as an argument 121 * to this method. 122 * On second and subsequent iterations the block builder that is applied is the resulting 123 * block builder of the prior iteration. 124 * 125 * @param builder the block builder 126 * @param block the block to transform 127 */ 128 default void acceptBlock(Block.Builder builder, Block block) { 129 for (Op op : block.ops()) { 130 builder = acceptOp(builder, op); 131 } 132 } 133 134 /** 135 * Transforms an operation to zero or more operations, appending those operations to a 136 * block builder. Returns a block builder to be used for transforming further operations, such 137 * as subsequent operations from the same block as the given operation. 138 * 139 * @param block the block builder. 140 * @param op the operation to transform. 141 * @return the block builder to append to for subsequent operations. 142 */ 143 Block.Builder acceptOp(Block.Builder block, Op op); 144 145 /** 146 * Returns a composed code transform that transforms an operation that first applies 147 * a block builder and operation to the function {@code f}, and then applies 148 * the resulting block builder and the same operation to {@link OpTransformer#acceptOp acceptOp} 149 * of the code transformer {@code after}. 150 * <p> 151 * If the code transformer {@code after} is {@code null} then it is as if a code transformer 152 * is applied that does nothing except return the block builder it was given. 153 * 154 * @param after the code transformer to apply after 155 * @param f the operation transformer function to apply before 156 * @return the composed code transformer 157 */ 158 static OpTransformer compose(OpTransformer after, BiFunction<Block.Builder, Op, Block.Builder> f) { 159 return after == null 160 ? f::apply 161 : (block, op) -> after.acceptOp(f.apply(block, op), op); 162 } 163 164 /** 165 * Returns a composed code transformer that first applies a block builder and operation to 166 * {@link OpTransformer#acceptOp acceptOp} of the code transformer {@code before}, 167 * and then applies resulting block builder and the same operation to the function {@code f}. 168 * <p> 169 * If the code transformer {@code before} is {@code null} then it is as if a code transformer 170 * is applied that does nothing except return the block builder it was given. 171 * 172 * @param before the code transformer to apply before 173 * @param f the operation transformer function to apply after 174 * @return the composed code transformer 175 */ 176 static OpTransformer andThen(OpTransformer before, BiFunction<Block.Builder, Op, Block.Builder> f) { 177 return before == null 178 ? f::apply 179 : (block, op) -> f.apply(before.acceptOp(block, op), op); 180 } 181 }