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.op;
 27 
 28 import java.io.IOException;
 29 import java.io.StringWriter;
 30 import java.io.Writer;
 31 import jdk.incubator.code.*;
 32 import jdk.incubator.code.type.FunctionType;
 33 import java.util.*;
 34 import java.util.function.Consumer;
 35 
 36 import static jdk.incubator.code.op.OpFactory.*;
 37 
 38 public final class AnfDialect {
 39 
 40     private AnfDialect() {
 41     }
 42 
 43     @OpDeclaration(AnfLetOp.NAME)
 44     public static final class AnfLetOp extends ExternalizableOp implements Op.Terminating, Op.Nested {
 45         public static final String NAME = "anf.let";
 46 
 47         public static class Builder {
 48             final Body.Builder ancestorBody;
 49             final TypeElement yieldType;
 50 
 51             Builder(Body.Builder ancestorBody, TypeElement yieldType) {
 52                 this.ancestorBody = ancestorBody;
 53                 this.yieldType = yieldType;
 54             }
 55 
 56             public AnfLetOp body(Consumer<Block.Builder> c) {
 57                 Body.Builder body = Body.Builder.of(ancestorBody, FunctionType.functionType(yieldType));
 58                 c.accept(body.entryBlock());
 59                 return new AnfLetOp(body);
 60             }
 61         }
 62 
 63         // Terminating operation is the in expression that yields the result for this operation
 64         // Any operation result in the entry block used by the terminating operation
 65         // or a descendant operation is a let binding
 66         final Body bindings;
 67 
 68         public AnfLetOp(ExternalizedOp def) {
 69             super(def);
 70 
 71             this.bindings = def.bodyDefinitions().get(0).build(this);
 72         }
 73 
 74         public AnfLetOp(AnfLetOp that, CopyContext cc, OpTransformer ot) {
 75             super(that, cc);
 76 
 77             this.bindings = that.bindings.transform(cc, ot).build(this);
 78         }
 79 
 80         @Override
 81         public Op transform(CopyContext cc, OpTransformer ot) {
 82             return new AnfLetOp(this, cc, ot);
 83         }
 84 
 85         public AnfLetOp(Body.Builder bodyBuilder) {
 86             super(NAME, List.of());
 87 
 88             this.bindings = bodyBuilder.build(this);
 89         }
 90 
 91         @Override
 92         public List<Body> bodies() {
 93             return List.of(bindings);
 94         }
 95 
 96         @Override
 97         public TypeElement resultType() {
 98             return this.bindings.yieldType();
 99         }
100     }
101 
102 
103     @OpDeclaration(AnfLetRecOp.NAME)
104     public static final class AnfLetRecOp extends ExternalizableOp implements Op.Terminating, Op.Nested {
105         public static final String NAME = "anf.letrec";
106 
107         public static class Builder {
108             final Body.Builder ancestorBody;
109             final TypeElement yieldType;
110 
111             Builder(Body.Builder ancestorBody, TypeElement yieldType) {
112                 this.ancestorBody = ancestorBody;
113                 this.yieldType = yieldType;
114             }
115 
116             public AnfLetRecOp body(Consumer<Block.Builder> c) {
117                 Body.Builder body = Body.Builder.of(ancestorBody, FunctionType.functionType(yieldType));
118                 c.accept(body.entryBlock());
119                 return new AnfLetRecOp(body);
120             }
121         }
122 
123         // Terminating operation is the in expression that yields the result for this operation
124         // Any operation result in the entry block used by the terminating operation
125         // or a descendant operation is a letrec binding
126         final Body bindings;
127 
128         public AnfLetRecOp(ExternalizedOp def) {
129             super(def);
130 
131             this.bindings = def.bodyDefinitions().get(0).build(this);
132         }
133 
134         public AnfLetRecOp(AnfLetRecOp that, CopyContext cc, OpTransformer ot) {
135             super(that, cc);
136 
137             this.bindings = that.bindings.transform(cc, ot).build(this);
138         }
139 
140         @Override
141         public Op transform(CopyContext cc, OpTransformer ot) {
142             return new AnfLetRecOp(this, cc, ot);
143         }
144 
145         public AnfLetRecOp(Body.Builder bodyBuilder) {
146             super(AnfLetRecOp.NAME, List.of());
147 
148             this.bindings = bodyBuilder.build(this);
149         }
150 
151         @Override
152         public List<Body> bodies() {
153             return List.of(bindings);
154         }
155 
156         @Override
157         public TypeElement resultType() {
158             return this.bindings.yieldType();
159         }
160 
161         public List<CoreOp.FuncOp> funcOps() {
162             List<Op> ops = bindings.entryBlock().ops();
163             return ops.subList(0, ops.size() - 1).stream()
164                     .<CoreOp.FuncOp>mapMulti((op, objectConsumer) -> {
165                         if (op instanceof CoreOp.FuncOp fop) {
166                             objectConsumer.accept(fop);
167                         }
168                     }).toList();
169         }
170     }
171 
172     @OpDeclaration(AnfIfOp.NAME)
173     public static final class AnfIfOp extends ExternalizableOp implements Op.Terminating, Op.Nested {
174         public static final String NAME = "anf.if";
175 
176         public static class ThenBuilder {
177             final Body.Builder ancestorBody;
178             final TypeElement yieldType;
179             final Value test;
180 
181             ThenBuilder(Body.Builder ancestorBody, TypeElement yieldType, Value test) {
182                 this.ancestorBody = ancestorBody;
183                 this.yieldType = yieldType;
184                 this.test = test;
185             }
186 
187             public ElseBuilder if_(Consumer<Block.Builder> c) {
188                 Body.Builder then_ = Body.Builder.of(ancestorBody,
189                         FunctionType.functionType(yieldType));
190                 c.accept(then_.entryBlock());
191 
192                 return new ElseBuilder(this, then_);
193             }
194         }
195 
196         public static class ElseBuilder {
197             final ThenBuilder thenBuilder;
198             final Body.Builder then_;
199 
200             public ElseBuilder(ThenBuilder thenBuilder, Body.Builder then_) {
201                 this.thenBuilder = thenBuilder;
202                 this.then_ = then_;
203             }
204 
205             public AnfIfOp else_(Consumer<Block.Builder> c) {
206                 Body.Builder else_ = Body.Builder.of(thenBuilder.ancestorBody,
207                         FunctionType.functionType(thenBuilder.yieldType));
208                 c.accept(else_.entryBlock());
209 
210                 return new AnfIfOp(thenBuilder.test, then_, else_);
211             }
212         }
213 
214         final Body then_, else_;
215 
216         public AnfIfOp(ExternalizableOp.ExternalizedOp def) {
217             super(def);
218 
219             this.then_ = def.bodyDefinitions().get(0).build(this);
220             this.else_ = def.bodyDefinitions().get(1).build(this);
221         }
222 
223         public AnfIfOp(AnfIfOp that, CopyContext cc, OpTransformer ot) {
224             super(that, cc);
225 
226             this.then_ = that.then_.transform(cc, ot).build(this);
227             this.else_ = that.else_.transform(cc, ot).build(this);
228         }
229 
230         @Override
231         public Op transform(CopyContext cc, OpTransformer ot) {
232             return new AnfIfOp(this, cc, ot);
233         }
234 
235         AnfIfOp(Value test, Body.Builder thenBodyBuilder, Body.Builder elseBodyBuilder) {
236             super(NAME, List.of(test));
237 
238             this.then_ = thenBodyBuilder.build(this);
239             this.else_ = elseBodyBuilder.build(this);
240         }
241 
242         public Value getTest() {
243             return this.operands().get(0);
244         }
245 
246         public Body _then() {
247             return then_;
248         }
249 
250         public Body _else() {
251             return else_;
252         }
253 
254         @Override
255         public List<Body> bodies() {
256             return List.of(then_, else_);
257         }
258 
259         @Override
260         public TypeElement resultType() {
261             return this.then_.yieldType();
262         }
263     }
264 
265     @OpFactory.OpDeclaration(AnfFuncOp.NAME)
266     public static final class AnfFuncOp extends ExternalizableOp implements Op.Nested {
267 
268         public static class Builder {
269             final Body.Builder ancestorBody;
270             final String funcName;
271             final FunctionType funcType;
272 
273             Builder(Body.Builder ancestorBody, String funcName, FunctionType funcType) {
274                 this.ancestorBody = ancestorBody;
275                 this.funcName = funcName;
276                 this.funcType = funcType;
277             }
278 
279             public AnfFuncOp body(Consumer<Block.Builder> c) {
280                 Body.Builder body = Body.Builder.of(ancestorBody, funcType);
281                 c.accept(body.entryBlock());
282                 return new AnfFuncOp(funcName, body);
283             }
284         }
285 
286         public static final String NAME = "anf.func";
287         public static final String ATTRIBUTE_FUNC_NAME = NAME + ".name";
288 
289         final String funcName;
290         final Body body;
291 
292         public static AnfFuncOp create(ExternalizedOp def) {
293             if (!def.operands().isEmpty()) {
294                 throw new IllegalStateException("Bad op " + def.name());
295             }
296 
297             String funcName = def.extractAttributeValue(ATTRIBUTE_FUNC_NAME, true,
298                     v -> switch (v) {
299                         case String s -> s;
300                         case null, default -> throw new UnsupportedOperationException("Unsupported func name value:" + v);
301                     });
302             return new AnfFuncOp(def, funcName);
303         }
304 
305         AnfFuncOp(ExternalizedOp def, String funcName) {
306             super(def);
307 
308             this.funcName = funcName;
309             this.body = def.bodyDefinitions().get(0).build(this);
310         }
311 
312         AnfFuncOp(AnfFuncOp that, CopyContext cc, OpTransformer oa) {
313             this(that, that.funcName, cc, oa);
314         }
315 
316         AnfFuncOp(AnfFuncOp that, String funcName, CopyContext cc, OpTransformer ot) {
317             super(that, cc);
318 
319             this.funcName = funcName;
320             this.body = that.body.transform(cc, ot).build(this);
321         }
322 
323         @Override
324         public AnfFuncOp transform(CopyContext cc, OpTransformer ot) {
325             return new AnfFuncOp(this, cc, ot);
326         }
327 
328         AnfFuncOp(String funcName, Body.Builder bodyBuilder) {
329             super(NAME,
330                     List.of());
331 
332             this.funcName = funcName;
333             this.body = bodyBuilder.build(this);
334         }
335 
336         @Override
337         public List<Body> bodies() {
338             return List.of(body);
339         }
340 
341         @Override
342         public Map<String, Object> attributes() {
343             HashMap<String, Object> m = new HashMap<>(super.attributes());
344             m.put("", funcName);
345             return Collections.unmodifiableMap(m);
346         }
347 
348         public FunctionType invokableType() {
349             return body.bodyType();
350         }
351 
352         public String funcName() {
353             return funcName;
354         }
355 
356         public Body body() {
357             return body;
358         }
359 
360         @Override
361         public TypeElement resultType() {
362             return invokableType();
363         }
364     }
365 
366     @OpFactory.OpDeclaration(AnfApply.NAME)
367     public static final class AnfApply extends ExternalizableOp implements Op.Terminating {
368         public static final String NAME = "anf.apply";
369 
370         public AnfApply(ExternalizedOp def) {
371             super(def);
372         }
373 
374         public AnfApply(AnfApply that, CopyContext cc) {
375             super(that, cc);
376         }
377 
378         @Override
379         public Op transform(CopyContext cc, OpTransformer ot) {
380             return new AnfApply(this, cc);
381         }
382 
383         @Override
384         public TypeElement resultType() {
385             FunctionType ft = (FunctionType) operands().get(0).type();
386             return ft.returnType();
387         }
388 
389         public AnfApply(List<Value> arguments) {
390             super(AnfApply.NAME, arguments);
391 
392             // First argument is func value
393             // Subsequent arguments are func arguments
394         }
395 
396 
397         public List<Value> args() {
398             return operands().subList(1, this.operands().size());
399         }
400     }
401 
402     @OpFactory.OpDeclaration(AnfApplyStub.NAME)
403     public static final class AnfApplyStub extends ExternalizableOp implements Op.Terminating {
404         public static final String NAME = "anf.apply.stub";
405         public static final String ATTRIBUTE_RESULT_TYPE = ".resultType";
406         public static final String ATTRIBUTE_CALLSITE_NAME = ".callsiteName";
407 
408         public final String callSiteName;
409         public final TypeElement resultType;
410 
411         public static AnfApplyStub create(ExternalizedOp def) {
412             if (!def.operands().isEmpty()) {
413                 throw new IllegalStateException("Bad op " + def.name());
414             }
415 
416             String callsiteName = def.extractAttributeValue(ATTRIBUTE_CALLSITE_NAME, true,
417                     v -> switch (v) {
418                         case String s -> s;
419                         case null, default -> throw new UnsupportedOperationException("Unsupported func name value:" + v);
420                     });
421             return new AnfApplyStub(def,callsiteName,def.resultType());
422         }
423 
424         public AnfApplyStub(ExternalizedOp def, String name, TypeElement resultType) {
425             super(def);
426             this.resultType = resultType;
427             this.callSiteName = name;
428         }
429 
430         public AnfApplyStub(AnfApplyStub that, CopyContext cc) {
431             super(that, cc);
432             this.callSiteName = that.callSiteName;
433             this.resultType = that.resultType;
434         }
435 
436         @Override
437         public Map<String, Object> attributes() {
438             HashMap<String, Object> m = new HashMap<>(super.attributes());
439             m.put("", callSiteName);
440             return Collections.unmodifiableMap(m);
441         }
442 
443         @Override
444         public Op transform(CopyContext cc, OpTransformer ot) {
445             return new AnfApplyStub(this, cc);
446         }
447 
448         public AnfApplyStub(String callSiteName, List<Value> arguments, TypeElement resultType) {
449             super(AnfApplyStub.NAME, arguments);
450             this.resultType = resultType;
451             this.callSiteName = callSiteName;
452 
453             // First argument is func value
454             // Subsequent arguments are func arguments
455         }
456 
457         @Override
458         public TypeElement resultType() {
459             return this.resultType;
460         }
461 
462         public List<Value> args() {
463             return operands().subList(1, this.operands().size());
464         }
465     }
466 
467     public static AnfLetRecOp.Builder letrec(Body.Builder ancestorBody, TypeElement yieldType) {
468         return new AnfLetRecOp.Builder(ancestorBody, yieldType);
469     }
470 
471     public static AnfLetRecOp letrec(Body.Builder body) {
472         return new AnfLetRecOp(body);
473     }
474 
475     public static AnfLetOp.Builder let(Body.Builder ancestorBody, TypeElement yieldType) {
476         return new AnfLetOp.Builder(ancestorBody, yieldType);
477     }
478 
479     public static AnfLetOp let(Body.Builder body) {
480         return new AnfLetOp(body);
481     }
482 
483     public static AnfIfOp.ThenBuilder if_(Body.Builder ancestorBody, TypeElement yieldType, Value test) {
484         return new AnfIfOp.ThenBuilder(ancestorBody, yieldType, test);
485     }
486 
487     public static AnfIfOp if_(Body.Builder then_, Body.Builder else_, Value test) {
488         return new AnfIfOp(test, then_, else_);
489     }
490 
491     public static AnfFuncOp.Builder func(Body.Builder ancestorBody, String funcName, FunctionType funcType) {
492         List<TypeElement> params = new ArrayList<>();
493         params.add(funcType.returnType());
494         params.addAll(funcType.parameterTypes());
495         return new AnfFuncOp.Builder(ancestorBody, funcName, FunctionType.functionType(funcType.returnType(), params));
496     }
497 
498     public static AnfFuncOp func(String funcName, Body.Builder body) {
499         return new AnfFuncOp(funcName, body);
500     }
501 
502     public static AnfApply apply(List<Value> arguments) {
503         return new AnfApply(arguments);
504     }
505     //public static AnfApplyStub applyStub(String name, List<Value> arguments, TypeElement type) { return new AnfApplyStub(name, arguments, type);}
506 }