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 }