From 4e190b95c34bfd62bd26fe02999e64cf09f1cc45 Mon Sep 17 00:00:00 2001 From: ike709 Date: Mon, 8 Sep 2025 15:02:47 -0500 Subject: [PATCH 1/5] Constant folding in `EmitPushValue()` --- DMCompiler/DM/Expressions/Binary.cs | 120 +++++++++++++++++++++++++++ DMCompiler/DM/Expressions/Ternary.cs | 5 ++ DMCompiler/DM/Expressions/Unary.cs | 15 ++++ 3 files changed, 140 insertions(+) diff --git a/DMCompiler/DM/Expressions/Binary.cs b/DMCompiler/DM/Expressions/Binary.cs index 8679fa8c53..3c52288de2 100644 --- a/DMCompiler/DM/Expressions/Binary.cs +++ b/DMCompiler/DM/Expressions/Binary.cs @@ -35,6 +35,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Add(); @@ -60,6 +65,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Subtract(); @@ -85,6 +95,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Multiply(); @@ -110,6 +125,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Divide(); @@ -135,6 +155,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Modulus(); @@ -163,6 +188,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.ModulusModulus(); @@ -188,6 +218,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Power(); @@ -213,6 +248,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BitShiftLeft(); @@ -238,6 +278,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BitShiftRight(); @@ -265,6 +310,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BinaryAnd(); @@ -290,6 +340,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BinaryXor(); @@ -315,6 +370,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.BinaryOr(); @@ -324,6 +384,11 @@ public override void EmitPushValue(ExpressionContext ctx) { // x == y internal sealed class Equal(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Equal(); @@ -333,6 +398,11 @@ public override void EmitPushValue(ExpressionContext ctx) { // x != y internal sealed class NotEqual(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.NotEqual(); @@ -342,6 +412,11 @@ public override void EmitPushValue(ExpressionContext ctx) { // x ~= y internal sealed class Equivalent(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Equivalent(); @@ -351,6 +426,11 @@ public override void EmitPushValue(ExpressionContext ctx) { // x ~! y internal sealed class NotEquivalent(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.NotEquivalent(); @@ -378,6 +458,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.GreaterThan(); @@ -387,6 +472,11 @@ public override void EmitPushValue(ExpressionContext ctx) { // x >= y internal sealed class GreaterThanOrEqual(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.GreaterThanOrEqual(); @@ -414,6 +504,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out // x < y internal sealed class LessThan(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.LessThan(); @@ -441,6 +536,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out // x <= y internal sealed class LessThanOrEqual(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.LessThanOrEqual(); @@ -485,6 +585,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + string endLabel = ctx.Proc.NewLabelName(); LHS.EmitPushValue(ctx); @@ -512,6 +617,21 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (LHS.TryAsConstant(ctx.Compiler, out var lhs)) { + if (lhs.IsTruthy()) { + if (RHS.TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + + RHS.EmitPushValue(ctx); + return; + } + + lhs.EmitPushValue(ctx); + return; + } + string endLabel = ctx.Proc.NewLabelName(); LHS.EmitPushValue(ctx); diff --git a/DMCompiler/DM/Expressions/Ternary.cs b/DMCompiler/DM/Expressions/Ternary.cs index c5b874a89b..8c5ba9afba 100644 --- a/DMCompiler/DM/Expressions/Ternary.cs +++ b/DMCompiler/DM/Expressions/Ternary.cs @@ -22,6 +22,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + string cLabel = ctx.Proc.NewLabelName(); string endLabel = ctx.Proc.NewLabelName(); diff --git a/DMCompiler/DM/Expressions/Unary.cs b/DMCompiler/DM/Expressions/Unary.cs index f6b07c94fb..c67d4b41a9 100644 --- a/DMCompiler/DM/Expressions/Unary.cs +++ b/DMCompiler/DM/Expressions/Unary.cs @@ -18,6 +18,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + Expr.EmitPushValue(ctx); ctx.Proc.Negate(); } @@ -33,6 +38,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + Expr.EmitPushValue(ctx); ctx.Proc.Not(); } @@ -49,6 +59,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + Expr.EmitPushValue(ctx); ctx.Proc.BinaryNot(); } From 28d04d77451cb9cc690ab55497eab1cca197a8e7 Mon Sep 17 00:00:00 2001 From: ike709 Date: Mon, 15 Sep 2025 12:05:09 -0500 Subject: [PATCH 2/5] fix modulo; less aggressive folding --- DMCompiler/DM/Expressions/Binary.cs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/DMCompiler/DM/Expressions/Binary.cs b/DMCompiler/DM/Expressions/Binary.cs index 3c52288de2..c05a7d3d4c 100644 --- a/DMCompiler/DM/Expressions/Binary.cs +++ b/DMCompiler/DM/Expressions/Binary.cs @@ -145,7 +145,7 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } if (lhs is Number lhsNum && rhs is Number rhsNum) { - constant = new Number(Location, lhsNum.Value % rhsNum.Value); + constant = new Number(Location, (int)lhsNum.Value % (int)rhsNum.Value); } else { constant = null; return false; @@ -384,11 +384,6 @@ public override void EmitPushValue(ExpressionContext ctx) { // x == y internal sealed class Equal(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { - if (TryAsConstant(ctx.Compiler, out var constant)) { - constant.EmitPushValue(ctx); - return; - } - LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Equal(); @@ -398,11 +393,6 @@ public override void EmitPushValue(ExpressionContext ctx) { // x != y internal sealed class NotEqual(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { - if (TryAsConstant(ctx.Compiler, out var constant)) { - constant.EmitPushValue(ctx); - return; - } - LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.NotEqual(); @@ -412,11 +402,6 @@ public override void EmitPushValue(ExpressionContext ctx) { // x ~= y internal sealed class Equivalent(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { - if (TryAsConstant(ctx.Compiler, out var constant)) { - constant.EmitPushValue(ctx); - return; - } - LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.Equivalent(); @@ -426,11 +411,6 @@ public override void EmitPushValue(ExpressionContext ctx) { // x ~! y internal sealed class NotEquivalent(Location location, DMExpression lhs, DMExpression rhs) : BinaryOp(location, lhs, rhs) { public override void EmitPushValue(ExpressionContext ctx) { - if (TryAsConstant(ctx.Compiler, out var constant)) { - constant.EmitPushValue(ctx); - return; - } - LHS.EmitPushValue(ctx); RHS.EmitPushValue(ctx); ctx.Proc.NotEquivalent(); From 5c8efcee130f4f5186a3bc2933ea8f60bda1e37e Mon Sep 17 00:00:00 2001 From: ike709 Date: Mon, 15 Sep 2025 12:05:31 -0500 Subject: [PATCH 3/5] make bitnot TryAsConstant() match runtime behavior --- DMCompiler/DM/Expressions/Unary.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DMCompiler/DM/Expressions/Unary.cs b/DMCompiler/DM/Expressions/Unary.cs index c67d4b41a9..4de2a46821 100644 --- a/DMCompiler/DM/Expressions/Unary.cs +++ b/DMCompiler/DM/Expressions/Unary.cs @@ -54,7 +54,7 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out if (!Expr.TryAsConstant(compiler, out constant) || constant is not Number constantNum) return false; - constant = new Number(Location, ~(int)constantNum.Value); + constant = new Number(Location, (~(int)constantNum.Value) & 0xFFFFFF); return true; } From c5373a5211c2e1b3dce3261650f46ab882074ad9 Mon Sep 17 00:00:00 2001 From: ike709 Date: Mon, 15 Sep 2025 12:17:54 -0500 Subject: [PATCH 4/5] cherry-pick test change from pr#885 --- Content.Tests/DMProject/Tests/Expression/edge_comparison.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm b/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm index 069fc4aaae..27c5a815ef 100644 --- a/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm +++ b/Content.Tests/DMProject/Tests/Expression/edge_comparison.dm @@ -1,18 +1,20 @@  /proc/RunTest() + // null violates the holy trichotomy here, with how it compares to an empty string. + ASSERT( (null > "") == 0 ) ASSERT( (null >= "") == 1 ) + ASSERT( (null == "") == 0 ) ASSERT( (null <= "") == 1 ) + ASSERT( (null < "") == 0 ) ASSERT( (null > 5) == 0 ) ASSERT( (null > -5) == 1 ) ASSERT( (null > "abc") == 0 ) - ASSERT( (null > "") == 0 ) ASSERT( (null > null) == 0 ) ASSERT( (null < 5) == 1 ) ASSERT( (null < -5) == 0 ) ASSERT( (null < "abc") == 1 ) - ASSERT( (null < "") == 0 ) ASSERT( (null < null) == 0 ) ASSERT( (0.15 <= null) == 0) From 61a802079093cdb3d918003c5112614dea38f9de Mon Sep 17 00:00:00 2001 From: ike709 Date: Mon, 15 Sep 2025 12:26:45 -0500 Subject: [PATCH 5/5] do a pass on Builtins.cs --- DMCompiler/DM/Expressions/Builtins.cs | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/DMCompiler/DM/Expressions/Builtins.cs b/DMCompiler/DM/Expressions/Builtins.cs index 6988c48c54..02f9a0accb 100644 --- a/DMCompiler/DM/Expressions/Builtins.cs +++ b/DMCompiler/DM/Expressions/Builtins.cs @@ -709,6 +709,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Sin(); } @@ -734,6 +739,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Cos(); } @@ -759,6 +769,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Tan(); } @@ -789,6 +804,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.ArcSin(); } @@ -819,6 +839,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.ArcCos(); } @@ -844,6 +869,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.ArcTan(); } @@ -873,6 +903,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + xExpr.EmitPushValue(ctx); yExpr.EmitPushValue(ctx); ctx.Proc.ArcTan2(); @@ -904,6 +939,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Sqrt(); } @@ -946,6 +986,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); if (baseExpr == null) { ctx.Proc.LogE(); @@ -976,6 +1021,11 @@ public override bool TryAsConstant(DMCompiler compiler, [NotNullWhen(true)] out } public override void EmitPushValue(ExpressionContext ctx) { + if (TryAsConstant(ctx.Compiler, out var constant)) { + constant.EmitPushValue(ctx); + return; + } + expr.EmitPushValue(ctx); ctx.Proc.Abs(); }