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.Objects; 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 performs no action on the block builder. 48 */ 49 OpTransformer NOOP_TRANSFORMER = (block, op) -> block; 50 51 /** 52 * A transformer that drops location information from operations. 53 */ 54 OpTransformer DROP_LOCATION_TRANSFORMER = (block, op) -> { 55 Op.Result r = block.op(op); 56 r.op().setLocation(Location.NO_LOCATION); 57 return block; 58 }; 59 60 /** 61 * A transformer that lowers operations that are {@link Op.Lowerable lowerable}, 62 * and copies other operations. 63 */ 64 OpTransformer LOWERING_TRANSFORMER = (block, op) -> { 65 if (op instanceof Op.Lowerable lop) { 66 return lop.lower(block); 67 } else { 68 block.op(op); 69 return block; 70 } 71 }; 72 73 /** 74 * Transforms a body starting from a block builder. 75 * 76 * @implSpec 77 * The default implementation {@link #acceptBlock(Block.Builder, Block) accepts} a block builder 78 * and a block for each block of the body, in order, using this operation transformer. 79 * The following sequence of actions is performed: 80 * <ol> 81 * <li> 82 * the body's entry block is mapped to the block builder, and the (input) block parameters of the 83 * body's entry block are mapped to the (output) values, using the builder's context. 84 * <li>for each (input) block in the body (except the entry block) an (output) block builder is created 85 * from the builder with the same parameter types as the (input) block, in order. 86 * The (input) block is mapped to the (output) builder, and the (input) block parameters are mapped to the 87 * (output) block parameters, using the builder's context. 88 * <li> 89 * for each (input) block in the body (in order) the (input) block is transformed 90 * by {@link #acceptBlock(Block.Builder, Block) accepting} the mapped (output) builder and 91 * (input) block, using this operation transformer. 92 * </ol> 93 * 94 * @param builder the block builder 95 * @param body the body to transform 96 * @param values the values to map to the body's entry block parameters 97 */ 98 default void acceptBody(Block.Builder builder, Body body, List<? extends Value> values) { 99 CopyContext cc = builder.context(); 100 101 // Map blocks up front, for forward referencing successors 102 for (Block block : body.blocks()) { 103 if (block.isEntryBlock()) { 104 cc.mapBlock(block, builder); 105 cc.mapValues(block.parameters(), values); 106 } else { 107 Block.Builder blockBuilder = builder.block(block.parameterTypes()); 108 cc.mapBlock(block, blockBuilder); 109 cc.mapValues(block.parameters(), blockBuilder.parameters()); 110 } 111 } 112 113 // Transform blocks 114 for (Block b : body.blocks()) { 115 acceptBlock(cc.getBlock(b), b); 116 } 117 } 118 119 /** 120 * Transforms a block starting from a block builder. 121 * 122 * @implSpec 123 * The default implementation {@link #acceptOp(Block.Builder, Op) accepts} a block builder 124 * and an operation for each operation of the block, in order, using this operation transformer. 125 * On first iteration the block builder that is applied is block builder passed as an argument 126 * to this method. 127 * On second and subsequent iterations the block builder that is applied is the resulting 128 * block builder of the prior iteration. 129 * 130 * @param builder the block builder 131 * @param block the block to transform 132 * @throws NullPointerException if a resulting block builder is null 133 */ 134 default void acceptBlock(Block.Builder builder, Block block) { 135 for (Op op : block.ops()) { 136 builder = acceptOp(builder, op); 137 // @@@ See andThen composition 138 Objects.requireNonNull(builder); 139 } 140 } 141 142 /** 143 * Transforms an operation to zero or more operations, appending those operations to a 144 * block builder. Returns a block builder to be used for transforming further operations, such 145 * as subsequent operations from the same block as the given operation. 146 * 147 * @param block the block builder. 148 * @param op the operation to transform. 149 * @return the block builder to append to for subsequent operations. 150 */ 151 Block.Builder acceptOp(Block.Builder block, Op op); 152 153 default OpTransformer compose(OpTransformer before) { 154 return before.andThen(this); 155 } 156 157 default OpTransformer andThen(OpTransformer after) { 158 if (after == NOOP_TRANSFORMER) { 159 return this; 160 } else if (this == NOOP_TRANSFORMER) { 161 return after; 162 } else { 163 return (bb, o) -> { 164 Block.Builder nbb = acceptOp(bb, o); 165 if (nbb != null) { 166 return after.acceptOp(nbb, o); 167 } else { 168 // @@@ This does not currently occur 169 return null; 170 } 171 }; 172 } 173 } 174 }