Skip to content

Commit

Permalink
merge: Initial optimizer (#1272)
Browse files Browse the repository at this point in the history
Ahhh!!!
  • Loading branch information
ice1000 authored Jan 4, 2025
2 parents 88dc38e + 3999ede commit 5c7390c
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler.free;

Expand Down Expand Up @@ -60,4 +60,8 @@ void switchCase(
);

void returnWith(@NotNull FreeJavaExpr expr);

default void unreachable() {
returnWith(invoke(Constants.PANIC, ImmutableSeq.empty()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ public void switchCase(
stmts.append(new FreeStmt.Return(assertFreeExpr(expr)));
}

@Override public void unreachable() {
stmts.append(FreeStmt.Unreachable.INSTANCE);
}

@Override
public @NotNull FreeJavaExpr mkNew(@NotNull MethodRef conRef, @NotNull ImmutableSeq<FreeJavaExpr> args) {
return FreeExprBuilderImpl.INSTANCE.mkNew(conRef, args);
Expand Down Expand Up @@ -191,16 +195,8 @@ public void switchCase(
return FreeExprBuilderImpl.INSTANCE.mkLambda(captures, method, builder);
}

@Override
public @NotNull FreeJavaExpr iconst(int i) {
return FreeExprBuilderImpl.INSTANCE.iconst(i);
}

@Override
public @NotNull FreeJavaExpr iconst(boolean b) {
return FreeExprBuilderImpl.INSTANCE.iconst(b);
}

@Override public @NotNull FreeJavaExpr iconst(int i) { return FreeExprBuilderImpl.INSTANCE.iconst(i); }
@Override public @NotNull FreeJavaExpr iconst(boolean b) { return FreeExprBuilderImpl.INSTANCE.iconst(b); }
@Override public @NotNull FreeJavaExpr aconst(@NotNull String value) {
return FreeExprBuilderImpl.INSTANCE.aconst(value);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler.free.morphism.free;

import kala.collection.immutable.ImmutableSeq;
import org.aya.compiler.free.morphism.free.FreeDecl.Clazz;
import org.aya.compiler.free.morphism.free.FreeDecl.ConstantField;
import org.aya.compiler.free.morphism.free.FreeDecl.Method;
import org.jetbrains.annotations.NotNull;

public interface FreeOptimizer {
static @NotNull Clazz optimizeClass(Clazz clazz) {
return (Clazz) optimize(clazz);
}

static @NotNull FreeDecl optimize(FreeDecl decl) {
return switch (decl) {
case Clazz(var metadata, var owner, var nested, var superclass, var members) -> {
var newMembers = members.map(FreeOptimizer::optimize);
yield new Clazz(metadata, owner, nested, superclass, newMembers);
}
case ConstantField field -> field;
case Method(var signature, var body) -> new Method(signature, body.flatMap(FreeOptimizer::optimize));
};
}

static @NotNull ImmutableSeq<FreeStmt> optimize(FreeStmt stmt) {
return switch (stmt) {
case FreeStmt.Switch(var elim, var cases, var branch, var defaultCase) -> {
branch = branch.map(it -> it.flatMap(FreeOptimizer::optimize));
defaultCase = defaultCase.flatMap(FreeOptimizer::optimize);
if (branch.isEmpty()) yield defaultCase;
if (defaultCase.sizeEquals(1) && defaultCase.getFirst() == FreeStmt.Unreachable.INSTANCE) {
if (branch.sizeEquals(1)) {
yield branch.getFirst();
} else if (branch.sizeGreaterThan(1)) {
yield ImmutableSeq.of(new FreeStmt.Switch(elim, cases.dropLast(1), branch.dropLast(1), branch.getLast()));
}
}
yield ImmutableSeq.of(new FreeStmt.Switch(elim, cases, branch, defaultCase));
}
case FreeStmt.Breakable(var stmts) ->
ImmutableSeq.of(new FreeStmt.Breakable(stmts.flatMap(FreeOptimizer::optimize)));
case FreeStmt.IfThenElse(var cond, var thenBlock, var elseBlock) -> {
var newThenBlock = thenBlock.flatMap(FreeOptimizer::optimize);
var newElseBlock = elseBlock == null ? null : elseBlock.flatMap(FreeOptimizer::optimize);
yield ImmutableSeq.of(new FreeStmt.IfThenElse(cond, newThenBlock, newElseBlock));
}
default -> ImmutableSeq.of(stmt);
};
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler.free.morphism.free;

Expand Down Expand Up @@ -121,6 +121,7 @@ private void runFree(@NotNull ArgumentProvider ap, @NotNull FreeCodeBuilder buil
private void runFree(@NotNull ArgumentProvider ap, @NotNull FreeCodeBuilder builder, @NotNull FreeStmt free) {
switch (free) {
case FreeStmt.Break _ -> builder.breakOut();
case FreeStmt.Unreachable _ -> builder.unreachable();
case FreeStmt.Breakable(var inner) -> builder.breakable(cb -> runFree(ap, cb, inner));
case FreeStmt.DeclareVariable mkVar -> bindVar(mkVar.theVar().index(), builder.makeVar(mkVar.type(), null));
case FreeStmt.Exec exec -> builder.exec(runFree(ap, builder, exec.expr()));
Expand Down Expand Up @@ -185,17 +186,8 @@ private void bindVar(int index, @NotNull LocalVariable userVar) {

private class SubscopeHandle implements AutoCloseable {
private final @UnknownNullability MutableMap<Integer, LocalVariable> oldBinding = binding;

public SubscopeHandle(
@NotNull MutableMap<Integer, LocalVariable> newScope
) {
binding = newScope;
}

@Override
public void close() {
binding = oldBinding;
}
public SubscopeHandle(@NotNull MutableMap<Integer, LocalVariable> newScope) { binding = newScope; }
@Override public void close() { binding = oldBinding; }
}

private @NotNull SubscopeHandle subscoped() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler.free.morphism.free;

Expand Down Expand Up @@ -32,6 +32,7 @@ record IfThenElse(@NotNull Condition cond, @NotNull ImmutableSeq<FreeStmt> thenB

record Breakable(@NotNull ImmutableSeq<FreeStmt> block) implements FreeStmt { }
enum Break implements FreeStmt { INSTANCE }
enum Unreachable implements FreeStmt { INSTANCE }

record Exec(@NotNull FreeExpr expr) implements FreeStmt { }
record Switch(@NotNull FreeVariable elim, @NotNull ImmutableIntSeq cases,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler.serializers;

Expand All @@ -22,16 +22,8 @@ public interface AyaSerializer {
String FIELD_EMPTYCALL = "ourCall";
String CLASS_PANIC = getJavaRef(Panic.class);

static void returnPanic(@NotNull FreeCodeBuilder builder) {
builder.returnWith(buildPanic(builder));
}

static void execPanic(@NotNull FreeCodeBuilder builder) {
builder.exec(buildPanic(builder));
}

static @NotNull FreeJavaExpr buildPanic(@NotNull FreeExprBuilder builder) {
return builder.invoke(Constants.PANIC, ImmutableSeq.empty());
builder.exec(builder.invoke(Constants.PANIC, ImmutableSeq.empty()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler.serializers;

Expand Down Expand Up @@ -105,7 +105,7 @@ protected void buildTelescope(@NotNull FreeCodeBuilder builder, @NotNull T unit,

cb.returnWith(result);
},
AyaSerializer::returnPanic);
builder1 -> builder1.unreachable());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.aya.compiler.free.FreeClassBuilder;
import org.aya.compiler.free.FreeJavaBuilder;
import org.aya.compiler.free.morphism.free.FreeJavaBuilderImpl;
import org.aya.compiler.free.morphism.free.FreeOptimizer;
import org.aya.compiler.free.morphism.free.FreeRunner;
import org.aya.compiler.free.morphism.source.SourceFreeJavaBuilder;
import org.aya.compiler.serializers.MatchySerializer.MatchyData;
Expand Down Expand Up @@ -80,6 +81,7 @@ private void doSerialize(@NotNull FreeClassBuilder builder, @NotNull TyckDef uni

public String serializeWithBestBuilder(ModuleResult unit) {
var freeJava = serialize(FreeJavaBuilderImpl.INSTANCE, unit);
freeJava = FreeOptimizer.optimizeClass(freeJava);
return new FreeRunner<>(SourceFreeJavaBuilder.create()).runFree(freeJava);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private void doSerialize(
switch (pat) {
case Pat.Misc misc -> {
switch (misc) {
case Absurd -> AyaSerializer.execPanic(builder);
case Absurd -> builder.unreachable();
case UntypedBind -> {
onMatchBind(builder, term);
onMatchSucc.accept(builder);
Expand Down Expand Up @@ -264,7 +264,7 @@ public PatternSerializer serialize(@NotNull FreeCodeBuilder builder, @NotNull Im
assert i > 0;
var realIdx = i - 1;
unit.get(realIdx).onSucc.accept(this, mBuilder, bindSize.get(realIdx));
}, AyaSerializer::returnPanic);
}, builder1 -> builder1.unreachable());

return this;
}
Expand Down
4 changes: 2 additions & 2 deletions jit-compiler/src/test/java/CompileTest.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.

import kala.collection.immutable.ImmutableSeq;
Expand Down Expand Up @@ -104,7 +104,7 @@ public record TyckResult(@NotNull ImmutableSeq<TyckDef> defs, @NotNull ResolveIn

public static @NotNull String serializeFrom(@NotNull TyckResult result) {
return new ModuleSerializer(result.info.shapeFactory())
.serialize(SourceFreeJavaBuilder.create(), new ModuleSerializer.ModuleResult(
.serializeWithBestBuilder(new ModuleSerializer.ModuleResult(
DumbModuleLoader.DUMB_MODULE_NAME, result.defs.filterIsInstance(TopLevelDef.class)));
}

Expand Down

0 comments on commit 5c7390c

Please sign in to comment.