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 oracle.code.triton; 27 28 import java.lang.reflect.code.Op; 29 import java.lang.reflect.code.Value; 30 import java.lang.reflect.code.analysis.Patterns; 31 import java.lang.reflect.code.op.CoreOp; 32 import java.lang.reflect.code.op.CoreOp.VarAccessOp.VarLoadOp; 33 import java.lang.reflect.code.op.CoreOp.VarAccessOp.VarStoreOp; 34 import java.lang.reflect.code.op.ExtendedOp; 35 import java.lang.reflect.code.type.JavaType; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 import static java.lang.reflect.code.analysis.Patterns.*; 40 41 // @@@ Very basic, limited, and partially correct 42 public class SimpleCountedForLoopInfo { 43 44 final ExtendedOp.JavaForOp fop; 45 46 SimpleCountedForLoopInfo(ExtendedOp.JavaForOp fop) { 47 this.fop = fop; 48 49 if (fop.init().yieldType().equals(JavaType.VOID)) { 50 throw new IllegalArgumentException("Loop variable externally initialized"); 51 } 52 if (fop.loopBody().entryBlock().parameters().size() > 1) { 53 throw new IllegalArgumentException("Two or more loop variables"); 54 } 55 } 56 57 public List<Op> startExpression() { 58 /* 59 ()Var<int> -> { 60 %12 : int = constant @"0"; 61 %13 : Var<int> = var %12 @"i"; 62 yield %13; 63 } 64 */ 65 66 Patterns.OpPattern p = opP(CoreOp.YieldOp.class, 67 opP(CoreOp.VarOp.class, 68 opResultP())); 69 70 // match against yieldOp 71 Op yieldOp = fop.init().entryBlock().ops().getLast(); 72 List<Value> matches = Patterns.match(null, yieldOp, p, (matchState, o) -> { 73 return matchState.matchedOperands(); 74 }); 75 if (matches == null) { 76 throw new IllegalArgumentException(); 77 } 78 Op.Result initValue = (Op.Result) matches.get(0); 79 80 return traverseOperands(initValue.op()); 81 } 82 83 public List<Op> endExpression() { 84 /* 85 (%14 : Var<int>)boolean -> { 86 %15 : int = var.load %14; 87 %16 : int = var.load %2; 88 %17 : boolean = lt %15 %16; 89 yield %17; 90 } 91 */ 92 93 Patterns.OpPattern p = opP(CoreOp.YieldOp.class, 94 opP(CoreOp.LtOp.class, 95 opP(VarLoadOp.class, 96 blockParameterP()), 97 opResultP())); 98 99 // match against yieldOp 100 Op yieldOp = fop.cond().entryBlock().ops().getLast(); 101 List<Value> matches = Patterns.match(null, yieldOp, p, (matchState, o) -> { 102 return matchState.matchedOperands(); 103 }); 104 if (matches == null) { 105 throw new IllegalArgumentException(); 106 } 107 Op.Result endValue = (Op.Result) matches.get(1); 108 109 return traverseOperands(endValue.op()); 110 } 111 112 public List<Op> stepExpression() { 113 /* 114 (%18 : Var<int>)void -> { 115 %19 : int = var.load %18; 116 %20 : int = constant @"1"; 117 %21 : int = add %19 %20; 118 var.store %18 %21; 119 yield; 120 } 121 */ 122 123 Patterns.OpPattern p = opP(VarStoreOp.class, 124 blockParameterP(), 125 opP(CoreOp.AddOp.class, 126 opP(VarLoadOp.class, blockParameterP()), 127 opResultP())); 128 129 // Match against last store op 130 // @@@ Add Block.prevOp() 131 Op storeOp = fop.update().entryBlock().ops().get(fop.update().entryBlock().ops().size() - 2); 132 List<Value> matches = Patterns.match(null, storeOp, p, (matchState, r) -> { 133 return matchState.matchedOperands(); 134 }); 135 if (matches == null) { 136 throw new IllegalArgumentException(); 137 } 138 Op.Result stepValue = (Op.Result) matches.get(2); 139 140 return traverseOperands(stepValue.op()); 141 } 142 143 static List<Op> traverseOperands(Op op) { 144 List<Op> ops = new ArrayList<>(); 145 traverseOperands(ops, op); 146 return ops; 147 } 148 149 // Hoist the expression 150 // @@@ should be pure and independent of the loop variable 151 static void traverseOperands(List<Op> ops, Op op) { 152 for (Value operand : op.operands()) { 153 if (operand.declaringBlock().parentBody() == op.ancestorBody()) { 154 if (operand instanceof Op.Result r) { 155 traverseOperands(ops, r.op()); 156 } 157 } 158 } 159 160 ops.add(op); 161 } 162 }