1 /*
  2  * Copyright (c) 2025, 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 package hat.phases;
 26 
 27 import hat.Accelerator;
 28 import hat.dialect.HATLocalVarOp;
 29 import hat.dialect.HATPrivateVarOp;
 30 import hat.dialect.HATVectorAddOp;
 31 import hat.dialect.HATVectorDivOp;
 32 import hat.dialect.HATVectorLoadOp;
 33 import hat.dialect.HATVectorMakeOfOp;
 34 import hat.dialect.HATVectorMulOp;
 35 import hat.dialect.HATVectorOfOp;
 36 import hat.dialect.HATVectorSubOp;
 37 import hat.dialect.HATVectorVarLoadOp;
 38 import hat.dialect.HATVectorVarOp;
 39 import hat.dialect.HATVectorOp;
 40 import hat.dialect.HATVectorBinaryOp;
 41 import hat.optools.OpTk;
 42 import hat.types._V;
 43 import jdk.incubator.code.Block;
 44 import jdk.incubator.code.CodeContext;
 45 import jdk.incubator.code.CodeElement;
 46 import jdk.incubator.code.Op;
 47 import jdk.incubator.code.TypeElement;
 48 import jdk.incubator.code.Value;
 49 import jdk.incubator.code.dialect.core.CoreOp;
 50 import jdk.incubator.code.dialect.java.JavaOp;
 51 
 52 import java.util.HashMap;
 53 import java.util.List;
 54 import java.util.Map;
 55 import java.util.Objects;
 56 import java.util.Set;
 57 import java.util.stream.Collectors;
 58 import java.util.stream.Stream;
 59 
 60 import static hat.dialect.HATPhaseUtils.VectorMetaData;
 61 import static hat.dialect.HATPhaseUtils.findNameVector;
 62 import static hat.dialect.HATPhaseUtils.findVectorTypeElement;
 63 import static hat.dialect.HATPhaseUtils.getVectorTypeInfo;
 64 import static hat.dialect.HATPhaseUtils.getWitdh;
 65 
 66 public abstract class HATDialectifyVectorOpPhase implements HATDialect {
 67 
 68     protected final Accelerator accelerator;
 69 
 70     @Override
 71     public Accelerator accelerator() {
 72         return this.accelerator;
 73     }
 74 
 75     private final OpView vectorOperation;
 76 
 77     public HATDialectifyVectorOpPhase(Accelerator accelerator, OpView vectorOperation) {
 78         this.accelerator = accelerator;
 79         this.vectorOperation = vectorOperation;
 80     }
 81 
 82     private HATVectorBinaryOp.OpType getBinaryOpType(JavaOp.InvokeOp invokeOp) {
 83         return switch (invokeOp.invokeDescriptor().name()) {
 84             case "add" -> HATVectorBinaryOp.OpType.ADD;
 85             case "sub" -> HATVectorBinaryOp.OpType.SUB;
 86             case "mul" -> HATVectorBinaryOp.OpType.MUL;
 87             case "div" -> HATVectorBinaryOp.OpType.DIV;
 88             default -> throw new RuntimeException("Unknown binary op " + invokeOp.invokeDescriptor().name());
 89         };
 90     }
 91 
 92     public enum OpView {
 93         FLOAT4_LOAD("float4View"),
 94         FLOAT2_LOAD("float2View"),
 95         OF("of"),
 96         ADD("add"),
 97         SUB("sub"),
 98         MUL("mul"),
 99         DIV("div"),
100         MAKE_MUTABLE("makeMutable");
101         final String methodName;
102 
103         OpView(String methodName) {
104             this.methodName = methodName;
105         }
106     }
107 
108     private boolean isVectorOperation(JavaOp.InvokeOp invokeOp) {
109         TypeElement typeElement = invokeOp.resultType();
110         Set<Class<?>> interfaces = Set.of();
111         try {
112             Class<?> aClass = Class.forName(typeElement.toString());
113             interfaces = OpTk.inspectAllInterfaces(aClass);
114         } catch (ClassNotFoundException _) {
115         }
116         return interfaces.contains(_V.class) && isMethod(invokeOp, vectorOperation.methodName);
117     }
118 
119     private boolean findIsSharedOrPrivate(CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
120         return findIsSharedOrPrivate(varLoadOp.operands().get(0));
121     }
122 
123     private boolean findIsSharedOrPrivate(Value v) {
124         if (v instanceof Op.Result r && r.op() instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
125             return findIsSharedOrPrivate(varLoadOp);
126         } else {
127             if (v instanceof CoreOp.Result r && (r.op() instanceof HATLocalVarOp || r.op() instanceof HATPrivateVarOp)) {
128                 return true;
129             }
130             return false;
131         }
132     }
133 
134     private HATVectorBinaryOp buildVectorBinaryOp(HATVectorBinaryOp.OpType opType, String varName, TypeElement resultType, TypeElement vectorElementType, int witdh, List<Value> outputOperands) {
135         return switch (opType) {
136             case ADD -> new HATVectorAddOp(varName, resultType, vectorElementType, witdh, outputOperands);
137             case SUB -> new HATVectorSubOp(varName, resultType, vectorElementType, witdh, outputOperands);
138             case MUL -> new HATVectorMulOp(varName, resultType, vectorElementType, witdh, outputOperands);
139             case DIV -> new HATVectorDivOp(varName, resultType, vectorElementType, witdh, outputOperands);
140         };
141     }
142 
143     private void insertVectorLoadOp(Block.Builder blockBuilder, JavaOp.InvokeOp invokeOp, CoreOp.VarOp varOp, boolean isShared) {
144         List<Value> inputOperandsVarOp = invokeOp.operands();
145         List<Value> outputOperandsVarOp = blockBuilder.context().getValues(inputOperandsVarOp);
146         VectorMetaData metaData = getVectorTypeInfo(invokeOp);
147         HATVectorOp memoryViewOp = new HATVectorLoadOp(varOp.varName(), varOp.resultType(), metaData.vectorTypeElement(), metaData.lanes(), isShared, outputOperandsVarOp);
148         Op.Result hatLocalResult = blockBuilder.op(memoryViewOp);
149         memoryViewOp.setLocation(varOp.location());
150         blockBuilder.context().mapValue(invokeOp.result(), hatLocalResult);
151     }
152 
153     private void inertVectorVarOp(Block.Builder blockBuilder, CoreOp.VarOp varOp, Map<Op, VectorMetaData> vectorMetaData) {
154         List<Value> inputOperandsVarOp = varOp.operands();
155         List<Value> outputOperandsVarOp = blockBuilder.context().getValues(inputOperandsVarOp);
156         VectorMetaData vmd = vectorMetaData.get(varOp);
157         HATVectorOp memoryViewOp = new HATVectorVarOp(varOp.varName(), varOp.resultType(), vmd.vectorTypeElement(), vmd.lanes(), outputOperandsVarOp);
158         Op.Result hatLocalResult = blockBuilder.op(memoryViewOp);
159         memoryViewOp.setLocation(varOp.location());
160         blockBuilder.context().mapValue(varOp.result(), hatLocalResult);
161     }
162 
163     public void insertBinaryOp(Block.Builder blockBuilder, CoreOp.VarOp varOp, JavaOp.InvokeOp invokeOp, Map<Op, VectorMetaData> vectorMetaData, Map<JavaOp.InvokeOp, HATVectorBinaryOp.OpType> binaryOperation) {
164         List<Value> inputOperands = invokeOp.operands();
165         List<Value> outputOperands = blockBuilder.context().getValues(inputOperands);
166         HATVectorBinaryOp.OpType binaryOpType = binaryOperation.get(invokeOp);
167         VectorMetaData vmd = vectorMetaData.get(invokeOp);
168         HATVectorOp memoryViewOp = buildVectorBinaryOp(binaryOpType, varOp.varName(), invokeOp.resultType(), vmd.vectorTypeElement(), vmd.lanes(), outputOperands);
169         Op.Result hatVectorOpResult = blockBuilder.op(memoryViewOp);
170         memoryViewOp.setLocation(varOp.location());
171         blockBuilder.context().mapValue(invokeOp.result(), hatVectorOpResult);
172     }
173 
174     private void insertVectorVarLoadOp(Block.Builder blockBuilder, CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
175         List<Value> inputOperandsVarLoad = varLoadOp.operands();
176         List<Value> outputOperandsVarLoad = blockBuilder.context().getValues(inputOperandsVarLoad);
177         String varLoadName = findNameVector(varLoadOp);
178         int lanes = getWitdh(varLoadOp);
179         TypeElement vectorElementType = findVectorTypeElement(varLoadOp);
180         HATVectorOp memoryViewOp = new HATVectorVarLoadOp(varLoadName, varLoadOp.resultType(), vectorElementType, lanes, outputOperandsVarLoad);
181         Op.Result hatVectorResult = blockBuilder.op(memoryViewOp);
182         memoryViewOp.setLocation(varLoadOp.location());
183         blockBuilder.context().mapValue(varLoadOp.result(), hatVectorResult);
184     }
185 
186     public void insertVectorBinaryOp(Block.Builder blockBuilder, JavaOp.InvokeOp invokeOp, Map<JavaOp.InvokeOp, HATVectorBinaryOp.OpType> binaryOperation) {
187         List<Value> inputOperands = invokeOp.operands();
188         List<Value> outputOperands = blockBuilder.context().getValues(inputOperands);
189         VectorMetaData vectorMetaData = getVectorTypeInfo(invokeOp);
190         HATVectorOp memoryViewOp = buildVectorBinaryOp(binaryOperation.get(invokeOp), "null", invokeOp.resultType(), vectorMetaData.vectorTypeElement(), vectorMetaData.lanes(), outputOperands);
191         Op.Result hatVectorOpResult = blockBuilder.op(memoryViewOp);
192         memoryViewOp.setLocation(invokeOp.location());
193         blockBuilder.context().mapValue(invokeOp.result(), hatVectorOpResult);
194     }
195 
196     public void insertVectorOfOp(Block.Builder blockBuilder, JavaOp.InvokeOp invokeOp, Map<Op, VectorMetaData> vectorMetaData) {
197         List<Value> inputOperandsVarOp = invokeOp.operands();
198         List<Value> outputOperandsVarOp = blockBuilder.context().getValues(inputOperandsVarOp);
199         VectorMetaData vmd = vectorMetaData.get(invokeOp);
200         HATVectorOfOp memoryViewOp = new HATVectorOfOp(invokeOp.resultType(), vmd.vectorTypeElement(), vmd.lanes(), outputOperandsVarOp);
201         Op.Result hatLocalResult = blockBuilder.op(memoryViewOp);
202         memoryViewOp.setLocation(invokeOp.location());
203         blockBuilder.context().mapValue(invokeOp.result(), hatLocalResult);
204     }
205 
206     public void insertVectorMakeOfOp(Block.Builder blockBuilder, JavaOp.InvokeOp invokeOp, Map<Op, VectorMetaData> vectorMetaData) {
207         List<Value> inputOperandsVarOp = invokeOp.operands();
208         List<Value> outputOperandsVarOp = blockBuilder.context().getValues(inputOperandsVarOp);
209         String varName = findNameVector(invokeOp.operands().getFirst());
210         VectorMetaData vmd = vectorMetaData.get(invokeOp);
211         HATVectorMakeOfOp makeOf = new HATVectorMakeOfOp(varName, invokeOp.resultType(), vmd.lanes(), outputOperandsVarOp);
212         Op.Result hatLocalResult = blockBuilder.op(makeOf);
213         makeOf.setLocation(invokeOp.location());
214         blockBuilder.context().mapValue(invokeOp.result(), hatLocalResult);
215     }
216 
217     private CoreOp.FuncOp dialectifyVectorLoad(CoreOp.FuncOp funcOp) {
218         var here = OpTk.CallSite.of(this.getClass(), "dialectifyVectorLoad");
219         Map<Op, VectorMetaData> vectorMetaData = new HashMap<>();
220         before(here, funcOp);
221         Stream<CodeElement<?, ?>> float4NodesInvolved = funcOp.elements()
222                 .mapMulti((codeElement, consumer) -> {
223                     if (codeElement instanceof CoreOp.VarOp varOp) {
224                         List<Value> inputOperandsVarOp = varOp.operands();
225                         for (Value inputOperand : inputOperandsVarOp) {
226                             if (inputOperand instanceof Op.Result result) {
227                                 if (result.op() instanceof JavaOp.InvokeOp invokeOp) {
228                                     if (isVectorOperation(invokeOp)) {
229                                         // Associate both ops to the vectorTypeInfo for easy
230                                         // access to type and lanes
231                                         VectorMetaData vectorTypeInfo = getVectorTypeInfo(invokeOp);
232                                         vectorMetaData.put(invokeOp, vectorTypeInfo);
233                                         vectorMetaData.put(varOp, vectorTypeInfo);
234                                         consumer.accept(invokeOp);
235                                         consumer.accept(varOp);
236                                     }
237                                 }
238                             }
239                         }
240                     }
241                 });
242 
243         Set<CodeElement<?, ?>> nodesInvolved = float4NodesInvolved.collect(Collectors.toSet());
244 
245         funcOp = OpTk.transform(here, funcOp, (blockBuilder, op) -> {
246             CodeContext context = blockBuilder.context();
247             if (!nodesInvolved.contains(op)) {
248                 blockBuilder.op(op);
249             } else if (op instanceof JavaOp.InvokeOp invokeOp) {
250                 // Don't insert the invoke node
251                 Op.Result result = invokeOp.result();
252                 List<Op.Result> collect = result.uses().stream().toList();
253                 boolean isShared = findIsSharedOrPrivate(invokeOp.operands().getFirst());
254                 for (Op.Result r : collect) {
255                     if (r.op() instanceof CoreOp.VarOp varOp) {
256                         insertVectorLoadOp(blockBuilder, invokeOp, varOp, isShared);
257                     }
258                 }
259             } else if (op instanceof CoreOp.VarOp varOp) {
260                 inertVectorVarOp(blockBuilder, varOp, vectorMetaData);
261             }
262             return blockBuilder;
263         });
264         after(here, funcOp);
265         return funcOp;
266     }
267 
268     private CoreOp.FuncOp dialectifyVectorOf(CoreOp.FuncOp funcOp) {
269         var here = OpTk.CallSite.of(this.getClass(), "dialectifyVectorOf");
270         Map<Op, VectorMetaData> vectorMetaData = new HashMap<>();
271         before(here, funcOp);
272         Stream<CodeElement<?, ?>> vectorNodes = funcOp.elements()
273                 .mapMulti((codeElement, consumer) -> {
274                     if (codeElement instanceof JavaOp.InvokeOp invokeOp) {
275                         if (isVectorOperation(invokeOp)) {
276                             consumer.accept(invokeOp);
277                             Set<Op.Result> uses = invokeOp.result().uses();
278                             for (Op.Result result : uses) {
279                                 if (result.op() instanceof CoreOp.VarOp varOp) {
280                                     consumer.accept(varOp);
281                                     VectorMetaData vectorTypeInfo = getVectorTypeInfo(invokeOp);
282                                     vectorMetaData.put(invokeOp, vectorTypeInfo);
283                                     vectorMetaData.put(varOp, vectorTypeInfo);
284                                 }
285                             }
286                         }
287                     }
288                 });
289 
290         Set<CodeElement<?, ?>> nodesInvolved = vectorNodes.collect(Collectors.toSet());
291 
292         funcOp = OpTk.transform(here, funcOp, (blockBuilder, op) -> {
293             if (!nodesInvolved.contains(op)) {
294                 blockBuilder.op(op);
295             } else if (op instanceof JavaOp.InvokeOp invokeOp) {
296                 insertVectorOfOp(blockBuilder, invokeOp, vectorMetaData);
297             } else if (op instanceof CoreOp.VarOp varOp) {
298                 inertVectorVarOp(blockBuilder, varOp, vectorMetaData);
299             }
300             return blockBuilder;
301         });
302         after(here, funcOp);
303         return funcOp;
304     }
305 
306     private CoreOp.FuncOp dialectifyVectorBinaryOps(CoreOp.FuncOp funcOp) {
307         var here = OpTk.CallSite.of(this.getClass(), "dialectifyVectorBinaryOps");
308         before(here, funcOp);
309         Map<JavaOp.InvokeOp, HATVectorBinaryOp.OpType> binaryOperation = new HashMap<>();
310         Map<Op, VectorMetaData> vectorMetaData = new HashMap<>();
311 
312         Stream<CodeElement<?, ?>> float4NodesInvolved = funcOp.elements()
313                 .mapMulti((codeElement, consumer) -> {
314                     if (codeElement instanceof CoreOp.VarOp varOp) {
315                         List<Value> inputOperandsVarOp = varOp.operands();
316                         for (Value inputOperand : inputOperandsVarOp) {
317                             if (inputOperand instanceof Op.Result result) {
318                                 if (result.op() instanceof JavaOp.InvokeOp invokeOp) {
319                                     if (isVectorOperation(invokeOp)) {
320                                         HATVectorBinaryOp.OpType binaryOpType = getBinaryOpType(invokeOp);
321                                         binaryOperation.put(invokeOp, binaryOpType);
322                                         VectorMetaData vectorTypeInfo = getVectorTypeInfo(invokeOp);
323                                         vectorMetaData.put(invokeOp, vectorTypeInfo);
324                                         vectorMetaData.put(varOp, vectorTypeInfo);
325                                         consumer.accept(invokeOp);
326                                         consumer.accept(varOp);
327                                     }
328                                 }
329                             }
330                         }
331                     }
332                 });
333 
334         Set<CodeElement<?, ?>> nodesInvolved = float4NodesInvolved.collect(Collectors.toSet());
335 
336         funcOp = OpTk.transform(here, funcOp, nodesInvolved::contains, (blockBuilder, op) -> {
337             if (op instanceof JavaOp.InvokeOp invokeOp) {
338                 Op.Result result = invokeOp.result();
339                 List<Op.Result> collect = result.uses().stream().toList();
340                 for (Op.Result r : collect) {
341                     if (r.op() instanceof CoreOp.VarOp varOp) {
342                         insertBinaryOp(blockBuilder, varOp, invokeOp, vectorMetaData, binaryOperation);
343                         break;
344                     }
345                 }
346             } else if (op instanceof CoreOp.VarOp varOp) {
347                 inertVectorVarOp(blockBuilder, varOp, vectorMetaData);
348             }
349             return blockBuilder;
350         });
351         after(here, funcOp);
352         return funcOp;
353     }
354 
355     private CoreOp.FuncOp dialectifyMutableOf(CoreOp.FuncOp funcOp) {
356         var here = OpTk.CallSite.of(this.getClass(), "dialectifyMutableOf");
357         before(here, funcOp);
358         Map<Op, VectorMetaData> vectorMetaData = new HashMap<>();
359         Stream<CodeElement<?, ?>> float4NodesInvolved = funcOp.elements()
360                 .mapMulti((codeElement, consumer) -> {
361                     if (codeElement instanceof JavaOp.InvokeOp invokeOp) {
362                         if (isVectorOperation(invokeOp)) {
363                             consumer.accept(invokeOp);
364                             VectorMetaData vectorTypeInfo = getVectorTypeInfo(invokeOp);
365                             vectorMetaData.put(invokeOp, vectorTypeInfo);
366                             Set<Op.Result> uses = invokeOp.result().uses();
367                             for (Op.Result result : uses) {
368                                 if (result.op() instanceof CoreOp.VarOp varOp) {
369                                     consumer.accept(varOp);
370                                     vectorMetaData.put(varOp, vectorTypeInfo);
371                                 }
372                             }
373                         }
374                     }
375                 });
376 
377         Set<CodeElement<?, ?>> nodesInvolved = float4NodesInvolved.collect(Collectors.toSet());
378 
379         funcOp = OpTk.transform(here, funcOp, (blockBuilder, op) -> {
380             if (!nodesInvolved.contains(op)) {
381                 blockBuilder.op(op);
382             } else if (op instanceof JavaOp.InvokeOp invokeOp) {
383                 insertVectorMakeOfOp(blockBuilder, invokeOp, vectorMetaData);
384             } else if (op instanceof CoreOp.VarOp varOp) {
385                 inertVectorVarOp(blockBuilder, varOp, vectorMetaData);
386             }
387             return blockBuilder;
388         });
389         after(here, funcOp);
390         return funcOp;
391     }
392 
393     private CoreOp.FuncOp dialectifyVectorBinaryWithConcatenationOps(CoreOp.FuncOp funcOp) {
394         var here = OpTk.CallSite.of(this.getClass(), "dialectifyBinaryWithConcatenation");
395         before(here, funcOp);
396         Map<JavaOp.InvokeOp, HATVectorBinaryOp.OpType> binaryOperation = new HashMap<>();
397         Stream<CodeElement<?, ?>> vectorNodes = funcOp.elements()
398                 .mapMulti((codeElement, consumer) -> {
399                     if (codeElement instanceof JavaOp.InvokeOp invokeOp) {
400                         if (isVectorOperation(invokeOp)) {
401                             List<Value> inputOperandsInvoke = invokeOp.operands();
402                             for (Value inputOperand : inputOperandsInvoke) {
403                                 if (inputOperand instanceof Op.Result r && r.op() instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
404                                     HATVectorBinaryOp.OpType binaryOpType = getBinaryOpType(invokeOp);
405                                     binaryOperation.put(invokeOp, binaryOpType);
406                                     consumer.accept(varLoadOp);
407                                     consumer.accept(invokeOp);
408                                 }
409                             }
410                         }
411                     } else if (codeElement instanceof HATVectorBinaryOp hatVectorBinaryOp) {
412                         List<Value> inputOperandsInvoke = hatVectorBinaryOp.operands();
413                         for (Value inputOperand : inputOperandsInvoke) {
414                             if (inputOperand instanceof Op.Result r && r.op() instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
415                                 consumer.accept(varLoadOp);
416                             }
417                         }
418                     }
419                 });
420 
421         Set<CodeElement<?, ?>> nodesInvolved = vectorNodes.collect(Collectors.toSet());
422         if (nodesInvolved.isEmpty()) {
423             return funcOp;
424         }
425         funcOp = OpTk.transform(here, funcOp, (blockBuilder, op) -> {
426             if (!nodesInvolved.contains(op)) {
427                 blockBuilder.op(op);
428             } else if (op instanceof JavaOp.InvokeOp invokeOp) {
429                 insertVectorBinaryOp(blockBuilder, invokeOp, binaryOperation);
430             } else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
431                 insertVectorVarLoadOp(blockBuilder, varLoadOp);
432             }
433             return blockBuilder;
434         });
435         after(here, funcOp);
436         return funcOp;
437     }
438 
439     @Override
440     public CoreOp.FuncOp apply(CoreOp.FuncOp funcOp) {
441         switch (Objects.requireNonNull(vectorOperation)) {
442             case FLOAT4_LOAD -> funcOp = dialectifyVectorLoad(funcOp);
443             case FLOAT2_LOAD ->  funcOp = dialectifyVectorLoad(funcOp);
444             case OF -> funcOp = dialectifyVectorOf(funcOp);
445             case MAKE_MUTABLE -> funcOp = dialectifyMutableOf(funcOp);
446             default -> {
447                 // Find binary operations
448                 funcOp = dialectifyVectorBinaryOps(funcOp);
449                 funcOp = dialectifyVectorBinaryWithConcatenationOps(funcOp);
450             }
451         }
452         return funcOp;
453     }
454 
455     public static class AddPhase extends HATDialectifyVectorOpPhase {
456 
457         public AddPhase(Accelerator accelerator) {
458             super(accelerator, OpView.ADD);
459         }
460     }
461 
462     public static class DivPhase extends HATDialectifyVectorOpPhase {
463 
464         public DivPhase(Accelerator accelerator) {
465             super(accelerator, OpView.DIV);
466         }
467     }
468 
469     public static class MakeMutable extends HATDialectifyVectorOpPhase {
470 
471         public MakeMutable(Accelerator accelerator) {
472             super(accelerator, OpView.MAKE_MUTABLE);
473         }
474     }
475 
476     public static class Float4LoadPhase extends HATDialectifyVectorOpPhase {
477 
478         public Float4LoadPhase(Accelerator accelerator) {
479             super(accelerator, OpView.FLOAT4_LOAD);
480         }
481     }
482 
483     public static class Float2LoadPhase extends HATDialectifyVectorOpPhase {
484 
485         public Float2LoadPhase(Accelerator accelerator) {
486             super(accelerator, OpView.FLOAT2_LOAD);
487         }
488     }
489 
490     public static class Float4OfPhase extends HATDialectifyVectorOpPhase {
491 
492         public Float4OfPhase(Accelerator accelerator) {
493             super(accelerator, OpView.OF);
494         }
495     }
496 
497     public static class MulPhase extends HATDialectifyVectorOpPhase {
498 
499         public MulPhase(Accelerator accelerator) {
500             super(accelerator, OpView.MUL);
501         }
502     }
503 
504     public static class SubPhase extends HATDialectifyVectorOpPhase {
505 
506         public SubPhase(Accelerator accelerator) {
507             super(accelerator, OpView.SUB);
508         }
509     }
510 }