From 2f4bf151f94945706bffa262ef42100ed761e1e6 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 6 Oct 2023 22:44:49 +0200 Subject: [PATCH 01/55] Factored out value instruction interface --- .../Model/ArithmeticInstruction.cs | 5 +---- .../Model/ArrayLengthInstruction.cs | 5 +---- .../OptimizingIr/Model/BoxInstruction.cs | 5 +---- .../OptimizingIr/Model/CallInstruction.cs | 5 +---- .../OptimizingIr/Model/IValueInstruction.cs | 18 ++++++++++++++++++ .../Model/LoadElementInstruction.cs | 5 +---- .../OptimizingIr/Model/LoadFieldInstruction.cs | 5 +---- .../OptimizingIr/Model/LoadInstruction.cs | 5 +---- .../Model/MemberCallInstruction.cs | 5 +---- .../OptimizingIr/Model/NewArrayInstruction.cs | 5 +---- .../OptimizingIr/Model/NewObjectInstruction.cs | 5 +---- 11 files changed, 28 insertions(+), 40 deletions(-) create mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs index f96c941066..7339ff446f 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs @@ -5,11 +5,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// Represents some kind of binary arithmetic instruction. /// -internal sealed class ArithmeticInstruction : InstructionBase +internal sealed class ArithmeticInstruction : InstructionBase, IValueInstruction { - /// - /// The register to store the result at. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs index 8220369d26..adc4158141 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs @@ -3,11 +3,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// An array length query. /// -internal sealed class ArrayLengthInstruction : InstructionBase +internal sealed class ArrayLengthInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the array length to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs index e650f81575..30c6f7925a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs @@ -5,11 +5,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// Valuetype element boxing. /// -internal sealed class BoxInstruction : InstructionBase +internal sealed class BoxInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the boxed value to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs index c21109a360..7c91e93b1e 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs @@ -6,11 +6,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// A procedure call. /// -internal sealed class CallInstruction : InstructionBase +internal sealed class CallInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the call result to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs new file mode 100644 index 0000000000..f3d76e4e8a --- /dev/null +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Draco.Compiler.Internal.OptimizingIr.Model; + +/// +/// An instruction that produces a result in a register. +/// +internal interface IValueInstruction +{ + /// + /// The register to store the result at. + /// + public Register Target { get; } +} diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs index 27eab508da..1102901791 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs @@ -6,11 +6,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// An array element access. /// -internal sealed class LoadElementInstruction : InstructionBase +internal sealed class LoadElementInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the array element to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs index be445035b5..dbb75cbbd2 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs @@ -5,11 +5,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// A field access. /// -internal sealed class LoadFieldInstruction : InstructionBase +internal sealed class LoadFieldInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the field to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs index 42809f9523..0abff1b8d1 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs @@ -3,11 +3,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// Loads a value from a local/global/argument. /// -internal sealed class LoadInstruction : InstructionBase +internal sealed class LoadInstruction : InstructionBase, IValueInstruction { - /// - /// The register to load to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs index f7679d553a..948c8d88b2 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs @@ -6,11 +6,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// A procedure call on a member. /// -internal sealed class MemberCallInstruction : InstructionBase +internal sealed class MemberCallInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the call result to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs index ba80953c52..d8a03d059a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs @@ -7,11 +7,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// An array instantiation. /// -internal sealed class NewArrayInstruction : InstructionBase +internal sealed class NewArrayInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the instantiated array to. - /// public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs index 5fbcf1fe3e..c9b4398fdc 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs @@ -6,11 +6,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// An object instantiation. /// -internal sealed class NewObjectInstruction : InstructionBase +internal sealed class NewObjectInstruction : InstructionBase, IValueInstruction { - /// - /// The register to write the instantiated object to. - /// public Register Target { get; set; } /// From a6b38b5582704709722e1a66b387e676bd45a1d8 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 6 Oct 2023 22:56:40 +0200 Subject: [PATCH 02/55] Hammering call instructions --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 10 ++-------- .../Internal/OptimizingIr/FunctionBodyCodegen.cs | 12 ++++++------ .../Internal/OptimizingIr/InstructionFactory.cs | 6 +++--- .../Internal/OptimizingIr/Model/CallInstruction.cs | 7 ++++--- .../OptimizingIr/Model/MemberCallInstruction.cs | 7 ++++--- .../OptimizingIr/Model/NewObjectInstruction.cs | 7 ++++--- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 26140be587..5608cade6c 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -293,7 +293,7 @@ private void EncodeInstruction(IInstruction instruction) // Arguments foreach (var arg in mcall.Arguments) this.EncodePush(arg); // Call - this.InstructionEncoder.OpCode(IsVirtual(mcall.Procedure) ? ILOpCode.Callvirt : ILOpCode.Call); + this.InstructionEncoder.OpCode(mcall.Procedure.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call); this.EncodeToken(mcall.Procedure); // Store result this.StoreLocal(mcall.Target); @@ -360,7 +360,7 @@ private void EncodeInstruction(IInstruction instruction) } } - private void EncodeToken(TypeSymbol symbol) + private void EncodeToken(Symbol symbol) { var handle = this.GetHandle(symbol); this.InstructionEncoder.Token(handle); @@ -472,10 +472,4 @@ private void StoreLocal(Register register) if (index is null) return; this.InstructionEncoder.StoreLocal(index.Value); } - - private static bool IsVirtual(IOperand operand) => operand switch - { - SymbolReference reference => (reference.Symbol as FunctionSymbol)?.IsVirtual ?? false, - _ => throw new ArgumentOutOfRangeException(nameof(operand)), - }; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index eb80671dff..10eac09e1a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -506,20 +506,20 @@ public override IOperand VisitFunctionGroupExpression(BoundFunctionGroupExpressi // TODO throw new System.NotImplementedException(); - private IOperand TranslateFunctionSymbol(FunctionSymbol symbol) => symbol switch + private FunctionSymbol TranslateFunctionSymbol(FunctionSymbol symbol) => symbol switch { - SourceFunctionSymbol func => this.DefineProcedure(func), - SynthetizedFunctionSymbol func => this.SynthetizeProcedure(func), - MetadataMethodSymbol m => new SymbolReference(m), + SourceFunctionSymbol func => this.DefineProcedure(func).Symbol, + SynthetizedFunctionSymbol func => this.SynthetizeProcedure(func).Symbol, + MetadataMethodSymbol m => m, FunctionInstanceSymbol i => this.TranslateFunctionInstanceSymbol(i), _ => throw new System.ArgumentOutOfRangeException(nameof(symbol)), }; - private IOperand TranslateFunctionInstanceSymbol(FunctionInstanceSymbol i) + private FunctionInstanceSymbol TranslateFunctionInstanceSymbol(FunctionInstanceSymbol i) { // NOTE: We visit the underlying instantiated symbol in case it's synthetized by us this.TranslateFunctionSymbol(i.GenericDefinition); - return new SymbolReference(i); + return i; } // NOTE: Parameters don't need loading, they are read-only values by default diff --git a/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs b/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs index b3259d8690..d7208e25aa 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs @@ -27,11 +27,11 @@ public static LoadFieldInstruction LoadField(Register target, IOperand receiver, public static JumpInstruction Jump(BasicBlock target) => new(target); public static BranchInstruction Branch(IOperand condition, BasicBlock then, BasicBlock @else) => new(condition, then, @else); - public static CallInstruction Call(Register target, IOperand proc, IEnumerable args) => + public static CallInstruction Call(Register target, FunctionSymbol proc, IEnumerable args) => new(target, proc, args); - public static MemberCallInstruction MemberCall(Register target, IOperand proc, IOperand receiver, IEnumerable args) => + public static MemberCallInstruction MemberCall(Register target, FunctionSymbol proc, IOperand receiver, IEnumerable args) => new(target, proc, receiver, args); - public static NewObjectInstruction NewObject(Register target, IOperand ctor, IEnumerable args) => + public static NewObjectInstruction NewObject(Register target, FunctionSymbol ctor, IEnumerable args) => new(target, ctor, args); public static NewArrayInstruction NewArray(Register target, TypeSymbol elementType, IEnumerable dimensions) => new(target, elementType, dimensions); diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs index 7c91e93b1e..b61559d69d 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -13,14 +14,14 @@ internal sealed class CallInstruction : InstructionBase, IValueInstruction /// /// The called procedure. /// - public IOperand Procedure { get; set; } + public FunctionSymbol Procedure { get; set; } /// /// The arguments that are passed to the procedure. /// public IList Arguments { get; set; } = new List(); - public CallInstruction(Register target, IOperand procedure, IEnumerable arguments) + public CallInstruction(Register target, FunctionSymbol procedure, IEnumerable arguments) { this.Target = target; this.Procedure = procedure; @@ -28,7 +29,7 @@ public CallInstruction(Register target, IOperand procedure, IEnumerable - $"{this.Target.ToOperandString()} := call {this.Procedure.ToOperandString()}({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; + $"{this.Target.ToOperandString()} := call [{this.Procedure.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; public override CallInstruction Clone() => new(this.Target, this.Procedure, this.Arguments); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs index 948c8d88b2..7a129b3910 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -13,7 +14,7 @@ internal sealed class MemberCallInstruction : InstructionBase, IValueInstruction /// /// The called procedure. /// - public IOperand Procedure { get; set; } + public FunctionSymbol Procedure { get; set; } /// /// The receiver the method is called on. @@ -25,7 +26,7 @@ internal sealed class MemberCallInstruction : InstructionBase, IValueInstruction /// public IList Arguments { get; set; } = new List(); - public MemberCallInstruction(Register target, IOperand procedure, IOperand receiver, IEnumerable arguments) + public MemberCallInstruction(Register target, FunctionSymbol procedure, IOperand receiver, IEnumerable arguments) { this.Target = target; this.Procedure = procedure; @@ -34,7 +35,7 @@ public MemberCallInstruction(Register target, IOperand procedure, IOperand recei } public override string ToString() => - $"{this.Target.ToOperandString()} := call {this.Receiver.ToOperandString()}.{this.Procedure.ToOperandString()}({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; + $"{this.Target.ToOperandString()} := call {this.Receiver.ToOperandString()}.[{this.Procedure.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; public override MemberCallInstruction Clone() => new(this.Target, this.Procedure, this.Receiver, this.Arguments); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs index c9b4398fdc..146c12a12b 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -13,14 +14,14 @@ internal sealed class NewObjectInstruction : InstructionBase, IValueInstruction /// /// The called constructor. /// - public IOperand Constructor { get; set; } + public FunctionSymbol Constructor { get; set; } /// /// The arguments that are passed to the constructor. /// public IList Arguments { get; set; } = new List(); - public NewObjectInstruction(Register target, IOperand constructor, IEnumerable arguments) + public NewObjectInstruction(Register target, FunctionSymbol constructor, IEnumerable arguments) { this.Target = target; this.Constructor = constructor; @@ -28,7 +29,7 @@ public NewObjectInstruction(Register target, IOperand constructor, IEnumerable - $"{this.Target.ToOperandString()} := new {this.Constructor.ToOperandString()}({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; + $"{this.Target.ToOperandString()} := new [{this.Constructor.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; public override NewObjectInstruction Clone() => new(this.Target, this.Constructor, this.Arguments); } From 5ba146a0870f7626432729a9c2b8c9682dec8a8c Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sat, 7 Oct 2023 23:06:25 +0200 Subject: [PATCH 03/55] Added operands sequence to instructions --- .../Internal/OptimizingIr/Model/ArithmeticInstruction.cs | 3 +++ .../Internal/OptimizingIr/Model/ArrayLengthInstruction.cs | 4 ++++ .../Internal/OptimizingIr/Model/BoxInstruction.cs | 3 +++ .../Internal/OptimizingIr/Model/BranchInstruction.cs | 1 + .../Internal/OptimizingIr/Model/CallInstruction.cs | 2 ++ src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs | 3 +++ .../Internal/OptimizingIr/Model/IInstruction.cs | 5 +++++ .../Internal/OptimizingIr/Model/InstructionBase.cs | 1 + .../Internal/OptimizingIr/Model/JumpInstruction.cs | 1 + .../Internal/OptimizingIr/Model/LoadElementInstruction.cs | 2 ++ .../Internal/OptimizingIr/Model/LoadFieldInstruction.cs | 3 +++ .../Internal/OptimizingIr/Model/LoadInstruction.cs | 4 ++++ .../Internal/OptimizingIr/Model/MemberCallInstruction.cs | 2 ++ .../Internal/OptimizingIr/Model/NewArrayInstruction.cs | 2 ++ .../Internal/OptimizingIr/Model/NewObjectInstruction.cs | 2 ++ .../Internal/OptimizingIr/Model/NopInstruction.cs | 3 +++ .../Internal/OptimizingIr/Model/RetInstruction.cs | 4 ++++ .../Internal/OptimizingIr/Model/SequencePoint.cs | 2 ++ .../Internal/OptimizingIr/Model/StoreElementInstruction.cs | 2 ++ .../Internal/OptimizingIr/Model/StoreFieldInstruction.cs | 3 +++ .../Internal/OptimizingIr/Model/StoreInstruction.cs | 4 ++++ 21 files changed, 56 insertions(+) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs index 7339ff446f..a20e572138 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -24,6 +25,8 @@ internal sealed class ArithmeticInstruction : InstructionBase, IValueInstruction /// public IOperand Right { get; set; } + public override IEnumerable Operands => new[] { this.Left, this.Right }; + public ArithmeticInstruction(Register target, ArithmeticOp op, IOperand left, IOperand right) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs index adc4158141..83a1506ebd 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Draco.Compiler.Internal.OptimizingIr.Model; /// @@ -12,6 +14,8 @@ internal sealed class ArrayLengthInstruction : InstructionBase, IValueInstructio /// public IOperand Array { get; set; } + public override IEnumerable Operands => new[] { this.Array }; + public ArrayLengthInstruction(Register target, IOperand array) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs index 30c6f7925a..e923f554ec 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -19,6 +20,8 @@ internal sealed class BoxInstruction : InstructionBase, IValueInstruction /// public IOperand Value { get; } + public override IEnumerable Operands => new[] { this.Value }; + public BoxInstruction(Register target, TypeSymbol boxedType, IOperand value) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs index 1eeae72b41..62e0686045 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace Draco.Compiler.Internal.OptimizingIr.Model; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs index b61559d69d..6b0a2e65c2 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs @@ -21,6 +21,8 @@ internal sealed class CallInstruction : InstructionBase, IValueInstruction /// public IList Arguments { get; set; } = new List(); + public override IEnumerable Operands => this.Arguments; + public CallInstruction(Register target, FunctionSymbol procedure, IEnumerable arguments) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs index 67a80174de..4d73d2fa93 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Linq; + namespace Draco.Compiler.Internal.OptimizingIr.Model; /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs index d328c7cd98..8e7d25bc33 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs @@ -37,6 +37,11 @@ internal interface IInstruction /// public IEnumerable JumpTargets { get; } + /// + /// The input operands of this instruction. + /// + public IEnumerable Operands { get; } + /// /// Clones this instruction. /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs index 538bd280c8..4b3c83a328 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs @@ -18,6 +18,7 @@ internal abstract class InstructionBase : IInstruction public virtual bool IsValidInUnreachableContext => false; public virtual IEnumerable JumpTargets => Enumerable.Empty(); IEnumerable IInstruction.JumpTargets => this.JumpTargets; + public virtual IEnumerable Operands => Enumerable.Empty(); public override abstract string ToString(); diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs index 537dcf85d9..37bc110ffe 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace Draco.Compiler.Internal.OptimizingIr.Model; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs index 1102901791..62ab16c4e8 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs @@ -20,6 +20,8 @@ internal sealed class LoadElementInstruction : InstructionBase, IValueInstructio /// public IList Indices { get; set; } = new List(); + public override IEnumerable Operands => this.Indices.Prepend(this.Array); + public LoadElementInstruction(Register target, IOperand array, IEnumerable indices) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs index dbb75cbbd2..1fa504f35d 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -19,6 +20,8 @@ internal sealed class LoadFieldInstruction : InstructionBase, IValueInstruction /// public FieldSymbol Member { get; set; } + public override IEnumerable Operands => new[] { this.Receiver }; + public LoadFieldInstruction(Register target, IOperand receiver, FieldSymbol member) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs index 0abff1b8d1..d29bffe841 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Draco.Compiler.Internal.OptimizingIr.Model; /// @@ -12,6 +14,8 @@ internal sealed class LoadInstruction : InstructionBase, IValueInstruction /// public IOperand Source { get; set; } + public override IEnumerable Operands => new[] { this.Source }; + public LoadInstruction(Register target, IOperand source) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs index 7a129b3910..e5d49feb37 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs @@ -26,6 +26,8 @@ internal sealed class MemberCallInstruction : InstructionBase, IValueInstruction /// public IList Arguments { get; set; } = new List(); + public override IEnumerable Operands => this.Arguments.Prepend(this.Receiver); + public MemberCallInstruction(Register target, FunctionSymbol procedure, IOperand receiver, IEnumerable arguments) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs index d8a03d059a..4e47ab6b11 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs @@ -21,6 +21,8 @@ internal sealed class NewArrayInstruction : InstructionBase, IValueInstruction /// public IList Dimensions { get; set; } = new List(); + public override IEnumerable Operands => this.Dimensions; + public NewArrayInstruction(Register target, TypeSymbol elementType, IEnumerable dimensions) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs index 146c12a12b..595222c096 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs @@ -21,6 +21,8 @@ internal sealed class NewObjectInstruction : InstructionBase, IValueInstruction /// public IList Arguments { get; set; } = new List(); + public override IEnumerable Operands => this.Arguments; + public NewObjectInstruction(Register target, FunctionSymbol constructor, IEnumerable arguments) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs index 12eaefa893..17a53ac1a7 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using System.Linq; + namespace Draco.Compiler.Internal.OptimizingIr.Model; /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs index 01ef9f36c9..c364a9be52 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Draco.Compiler.Internal.OptimizingIr.Model; /// @@ -12,6 +14,8 @@ internal sealed class RetInstruction : InstructionBase /// public IOperand Value { get; set; } + public override IEnumerable Operands => new[] { this.Value }; + public RetInstruction(IOperand value) { this.Value = value; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs index 20ed6f6509..f912d5d8c3 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Linq; using System.Text; using Draco.Compiler.Api.Syntax; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs index 8b6263074d..abbfb97615 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs @@ -23,6 +23,8 @@ internal sealed class StoreElementInstruction : InstructionBase /// public IOperand Source { get; set; } + public override IEnumerable Operands => this.Indices.Prepend(this.TargetArray).Append(this.Source); + public StoreElementInstruction(IOperand targetArray, IEnumerable indices, IOperand source) { this.TargetArray = targetArray; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs index 6212a18387..d3eadf439b 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -22,6 +23,8 @@ internal sealed class StoreFieldInstruction : InstructionBase /// public IOperand Source { get; set; } + public override IEnumerable Operands => new[] { this.Receiver, this.Source }; + public StoreFieldInstruction(IOperand receiver, FieldSymbol member, IOperand source) { this.Receiver = receiver; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs index 03bbb91f40..1b0ebb5027 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Draco.Compiler.Internal.OptimizingIr.Model; /// @@ -15,6 +17,8 @@ internal sealed class StoreInstruction : InstructionBase /// public IOperand Source { get; set; } + public override IEnumerable Operands => new[] { this.Target, this.Source }; + public StoreInstruction(IOperand target, IOperand source) { this.Target = target; From 94208c422ddf0d70558b4705fc4df939999e58c2 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sat, 7 Oct 2023 23:37:02 +0200 Subject: [PATCH 04/55] Create Stackifier.cs --- .../Internal/OptimizingIr/Stackifier.cs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs new file mode 100644 index 0000000000..0b125f18a0 --- /dev/null +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Draco.Compiler.Internal.OptimizingIr.Model; + +namespace Draco.Compiler.Internal.OptimizingIr; + +/// +/// Utility to reorder and annotate the register-based IR code to have better codegen on the CIL stack-machine. +/// +internal sealed class Stackifier +{ + private static ImmutableDictionary CountRegisterUses(IEnumerable instructions) + { + var registerUses = ImmutableDictionary.CreateBuilder(); + // Definition sites initialize to 0 + foreach (var instruction in instructions.OfType()) registerUses.Add(instruction.Target, 0); + // Count uses + foreach (var reg in instructions.SelectMany(instr => instr.Operands).OfType()) + { + ++registerUses[reg]; + } + return registerUses.ToImmutable(); + } + + private readonly IProcedure procedure; + private readonly ImmutableDictionary registerUses; + + public Stackifier(IProcedure procedure) + { + this.procedure = procedure; + var instructions = procedure.BasicBlocks.Values.SelectMany(bb => bb.Instructions); + // Count the number of register uses + this.registerUses = CountRegisterUses(instructions); + } + + /// + /// Stackifies the given basic block. + /// + /// The basic block to stackify. + /// The index of the instructions that has to leak onto registers. + public ImmutableArray Stackify(IBasicBlock basicBlock) + { + if (basicBlock.Procedure != this.procedure) + { + throw new ArgumentException("only basic-blocks belonging to the specified procedure can be stackified", nameof(basicBlock)); + } + + var instructions = basicBlock.Instructions.ToImmutableArray(); + var commitPoints = ImmutableArray.CreateBuilder(); + var index = basicBlock.InstructionCount; + while (index > 0) + { + --index; + // This is a commit-point + commitPoints.Add(index); + // Recover the longest tree backwards + this.RecoverTree(instructions, ref index); + } + + // Reverse for convenience + commitPoints.Reverse(); + return commitPoints.ToImmutable(); + } + + private bool RecoverTree(ImmutableArray instructions, ref int offset) + { + var instr = instructions[offset]; + var stopped = false; + + foreach (var op in instr.Operands.Reverse()) + { + // Not a register, pushed some other way, does not break tree + if (op is not Register reg) continue; + + // If we have a single-use register as a result immediately before this instruction, + // all good, part of the tree + if (!stopped + && this.registerUses[reg] == 1 + && instructions[offset - 1] is IValueInstruction valueInstr + && valueInstr.Target == reg) + { + --offset; + var childStopped = this.RecoverTree(instructions, ref offset); + // If child recovery broke the tree, we break too + if (childStopped) stopped = true; + continue; + } + + // Match failure, need to break the tree + stopped = true; + } + + return stopped; + } +} From 59a7d3fe1ed03706e476e59473a05ab98ac01e16 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sat, 7 Oct 2023 23:38:56 +0200 Subject: [PATCH 05/55] Update CilCodegen.cs --- .../Internal/Codegen/CilCodegen.cs | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 5608cade6c..cc59528c51 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -366,34 +366,6 @@ private void EncodeToken(Symbol symbol) this.InstructionEncoder.Token(handle); } - private void EncodeToken(IOperand operand) - { - switch (operand) - { - case IProcedure proc: - { - // Regular procedure call - var handle = this.GetProcedureDefinitionHandle(proc); - this.InstructionEncoder.Token(handle); - break; - } - case SymbolReference symbolRef when symbolRef.Symbol is TypeSymbol type: - { - this.EncodeToken(type); - break; - } - case SymbolReference symbolRef: - { - // Regular lookup - var handle = this.GetHandle(symbolRef.Symbol); - this.InstructionEncoder.Token(handle); - break; - } - default: - throw new ArgumentOutOfRangeException(nameof(operand)); - } - } - private void EncodePush(IOperand operand) { switch (operand) From 8b23b07156e8727ed2636c08c9029e89daf2921d Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sun, 8 Oct 2023 10:00:35 +0200 Subject: [PATCH 06/55] Update Stackifier.cs --- .../Internal/OptimizingIr/Stackifier.cs | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs index 0b125f18a0..f1b14449f3 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -13,6 +13,18 @@ namespace Draco.Compiler.Internal.OptimizingIr; /// internal sealed class Stackifier { + /// + /// Stackifies the given procedure without rearranging instructions. + /// + /// The procedure to stackify. + /// The registers that need to be saved to locals. The rest can stay on the stack. + public static ImmutableHashSet Stackify(IProcedure procedure) + { + var stackifier = new Stackifier(procedure); + foreach (var bb in procedure.BasicBlocks.Values) stackifier.Stackify(bb); + return stackifier.savedRegisters.ToImmutable(); + } + private static ImmutableDictionary CountRegisterUses(IEnumerable instructions) { var registerUses = ImmutableDictionary.CreateBuilder(); @@ -28,8 +40,9 @@ private static ImmutableDictionary CountRegisterUses(IEnumerable< private readonly IProcedure procedure; private readonly ImmutableDictionary registerUses; + private readonly ImmutableHashSet.Builder savedRegisters = ImmutableHashSet.CreateBuilder(); - public Stackifier(IProcedure procedure) + private Stackifier(IProcedure procedure) { this.procedure = procedure; var instructions = procedure.BasicBlocks.Values.SelectMany(bb => bb.Instructions); @@ -37,38 +50,23 @@ public Stackifier(IProcedure procedure) this.registerUses = CountRegisterUses(instructions); } - /// - /// Stackifies the given basic block. - /// - /// The basic block to stackify. - /// The index of the instructions that has to leak onto registers. - public ImmutableArray Stackify(IBasicBlock basicBlock) + private void Stackify(IBasicBlock basicBlock) { - if (basicBlock.Procedure != this.procedure) + var instr = basicBlock.LastInstruction; + while (instr is not null) { - throw new ArgumentException("only basic-blocks belonging to the specified procedure can be stackified", nameof(basicBlock)); - } - - var instructions = basicBlock.Instructions.ToImmutableArray(); - var commitPoints = ImmutableArray.CreateBuilder(); - var index = basicBlock.InstructionCount; - while (index > 0) - { - --index; - // This is a commit-point - commitPoints.Add(index); + // This instruction has to have its registers saved + if (instr is IValueInstruction valueInstr) this.savedRegisters.Add(valueInstr.Target); // Recover the longest tree backwards - this.RecoverTree(instructions, ref index); + this.RecoverTree(ref instr); + // Step back + instr = instr.Prev; } - - // Reverse for convenience - commitPoints.Reverse(); - return commitPoints.ToImmutable(); } - private bool RecoverTree(ImmutableArray instructions, ref int offset) + private bool RecoverTree(ref IInstruction instrIterator) { - var instr = instructions[offset]; + var instr = instrIterator; var stopped = false; foreach (var op in instr.Operands.Reverse()) @@ -80,11 +78,11 @@ private bool RecoverTree(ImmutableArray instructions, ref int offs // all good, part of the tree if (!stopped && this.registerUses[reg] == 1 - && instructions[offset - 1] is IValueInstruction valueInstr + && instrIterator.Prev is IValueInstruction valueInstr && valueInstr.Target == reg) { - --offset; - var childStopped = this.RecoverTree(instructions, ref offset); + instrIterator = instrIterator.Prev; + var childStopped = this.RecoverTree(ref instrIterator); // If child recovery broke the tree, we break too if (childStopped) stopped = true; continue; From 1b4c07d29b9a3c6306a11aa2a82d2c419e38b5f3 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sun, 8 Oct 2023 10:30:13 +0200 Subject: [PATCH 07/55] Almost working stackifier --- .../Internal/Codegen/CilCodegen.cs | 24 +++++++++++++++++++ .../Internal/OptimizingIr/Stackifier.cs | 9 ++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index cc59528c51..7a30a24000 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using Draco.Compiler.Internal.OptimizingIr; using Draco.Compiler.Internal.OptimizingIr.Model; using Draco.Compiler.Internal.Symbols; using Draco.Compiler.Internal.Symbols.Synthetized; @@ -33,13 +35,31 @@ internal sealed class CilCodegen private readonly MetadataCodegen metadataCodegen; private readonly IProcedure procedure; + private readonly ImmutableHashSet? stackifiedRegisters; private readonly Dictionary labels = new(); private readonly Dictionary allocatedLocals = new(); + // NOTE: The current stackification attempt is FLAWED + // Imagine this situation: + // + // r1 := load loc0 + // r2 := box 1 as object + // store r1[0] := r2 + // + // We stackify it and get + // + // load loc0 + // box 1 as object + // store r1[0] + // + // OOPS! The index "leaked behind" the value, reversing the order + // We might need to structure the instructions in a tree after all + public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) { this.metadataCodegen = metadataCodegen; this.procedure = procedure; + this.stackifiedRegisters = Stackifier.Stackify(procedure); var codeBuilder = new BlobBuilder(); var controlFlowBuilder = new ControlFlowBuilder(); @@ -426,6 +446,8 @@ private void LoadLocal(Local local) private void LoadLocal(Register register) { + // Register got stackified + if (this.stackifiedRegisters?.Contains(register) ?? false) return; var index = this.GetRegisterIndex(register); if (index is null) return; this.InstructionEncoder.LoadLocal(index.Value); @@ -440,6 +462,8 @@ private void StoreLocal(Local local) private void StoreLocal(Register register) { + // Register got stackified + if (this.stackifiedRegisters?.Contains(register) ?? false) return; var index = this.GetRegisterIndex(register); if (index is null) return; this.InstructionEncoder.StoreLocal(index.Value); diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs index f1b14449f3..75fcf59e15 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -17,12 +17,15 @@ internal sealed class Stackifier /// Stackifies the given procedure without rearranging instructions. /// /// The procedure to stackify. - /// The registers that need to be saved to locals. The rest can stay on the stack. + /// The registers that got stackified. public static ImmutableHashSet Stackify(IProcedure procedure) { var stackifier = new Stackifier(procedure); foreach (var bb in procedure.BasicBlocks.Values) stackifier.Stackify(bb); - return stackifier.savedRegisters.ToImmutable(); + // Subtract to get stackified regs + return stackifier.registerUses.Keys + .Except(stackifier.savedRegisters) + .ToImmutableHashSet(); } private static ImmutableDictionary CountRegisterUses(IEnumerable instructions) @@ -40,7 +43,7 @@ private static ImmutableDictionary CountRegisterUses(IEnumerable< private readonly IProcedure procedure; private readonly ImmutableDictionary registerUses; - private readonly ImmutableHashSet.Builder savedRegisters = ImmutableHashSet.CreateBuilder(); + private readonly HashSet savedRegisters = new(); private Stackifier(IProcedure procedure) { From 4752f4e96da1fae30492024357350fa362c39b4e Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sun, 8 Oct 2023 11:52:58 +0200 Subject: [PATCH 08/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 7a30a24000..f9499c782e 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -371,7 +371,7 @@ private void EncodeInstruction(IInstruction instruction) // Box it this.InstructionEncoder.OpCode(ILOpCode.Box); this.EncodeToken(box.Value.Type!); - // Sore result + // Store result this.StoreLocal(box.Target); break; } From 56fcf6273c92ad6b5bad271f85c9f237284ee308 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sun, 8 Oct 2023 13:11:25 +0200 Subject: [PATCH 09/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index f9499c782e..4c9d46f6f4 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -35,7 +35,6 @@ internal sealed class CilCodegen private readonly MetadataCodegen metadataCodegen; private readonly IProcedure procedure; - private readonly ImmutableHashSet? stackifiedRegisters; private readonly Dictionary labels = new(); private readonly Dictionary allocatedLocals = new(); @@ -59,7 +58,6 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) { this.metadataCodegen = metadataCodegen; this.procedure = procedure; - this.stackifiedRegisters = Stackifier.Stackify(procedure); var codeBuilder = new BlobBuilder(); var controlFlowBuilder = new ControlFlowBuilder(); @@ -446,8 +444,6 @@ private void LoadLocal(Local local) private void LoadLocal(Register register) { - // Register got stackified - if (this.stackifiedRegisters?.Contains(register) ?? false) return; var index = this.GetRegisterIndex(register); if (index is null) return; this.InstructionEncoder.LoadLocal(index.Value); @@ -462,8 +458,6 @@ private void StoreLocal(Local local) private void StoreLocal(Register register) { - // Register got stackified - if (this.stackifiedRegisters?.Contains(register) ?? false) return; var index = this.GetRegisterIndex(register); if (index is null) return; this.InstructionEncoder.StoreLocal(index.Value); From 94191bc5f9d16155d81f3ed7a2ad9be133b7c2b4 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sun, 8 Oct 2023 22:38:52 +0200 Subject: [PATCH 10/55] Eliminated most of symbol ref --- .../Internal/Codegen/CilCodegen.cs | 18 ------------------ .../OptimizingIr/Model/SymbolReference.cs | 15 --------------- 2 files changed, 33 deletions(-) delete mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/SymbolReference.cs diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 4c9d46f6f4..5fbac54d0a 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -69,12 +69,6 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) private UserStringHandle GetStringLiteralHandle(string text) => this.metadataCodegen.GetStringLiteralHandle(text); private EntityHandle GetHandle(Symbol symbol) => this.metadataCodegen.GetEntityHandle(symbol); - private EntityHandle GetHandle(IOperand operand) => operand switch - { - IProcedure proc => this.GetProcedureDefinitionHandle(proc), - SymbolReference symbolRef => this.GetHandle(symbolRef.Symbol), - _ => throw new ArgumentOutOfRangeException(nameof(operand)), - }; // TODO: Parameters don't handle unit yet, it introduces some signature problems private int GetParameterIndex(Parameter parameter) => parameter.Index; @@ -193,10 +187,6 @@ private void EncodeInstruction(IInstruction instruction) this.InstructionEncoder.OpCode(ILOpCode.Ldsfld); this.InstructionEncoder.Token(this.GetGlobalReferenceHandle(global)); break; - case SymbolReference symbol: - this.InstructionEncoder.OpCode(ILOpCode.Ldsfld); - this.InstructionEncoder.Token(this.GetHandle(symbol)); - break; default: throw new InvalidOperationException(); } @@ -250,11 +240,6 @@ private void EncodeInstruction(IInstruction instruction) this.InstructionEncoder.OpCode(ILOpCode.Stsfld); this.InstructionEncoder.Token(this.GetGlobalReferenceHandle(global)); break; - case SymbolReference symbol: - this.EncodePush(store.Source); - this.InstructionEncoder.OpCode(ILOpCode.Stsfld); - this.InstructionEncoder.Token(this.GetHandle(symbol)); - break; default: throw new InvalidOperationException(); } @@ -396,9 +381,6 @@ private void EncodePush(IOperand operand) case Parameter p: this.InstructionEncoder.LoadArgument(this.GetParameterIndex(p)); break; - case SymbolReference s when s.Symbol is ModuleSymbol module: - this.InstructionEncoder.Token(this.GetHandle(module)); - break; case Address a: switch (a.Operand) { diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/SymbolReference.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/SymbolReference.cs deleted file mode 100644 index 47e7fdb320..0000000000 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/SymbolReference.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Draco.Compiler.Internal.Symbols; - -namespace Draco.Compiler.Internal.OptimizingIr.Model; - -/// -/// A symbolic reference. -/// -/// The symbol referenced. -internal readonly record struct SymbolReference(Symbol Symbol) : IOperand -{ - public TypeSymbol? Type => (this.Symbol as ITypedSymbol)?.Type; - - public override string ToString() => this.ToOperandString(); - public string ToOperandString() => $"[{this.Symbol.FullName}]"; -} From d63d85508da4f05c36b9dc0d99a67ae073b1bd17 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sun, 8 Oct 2023 23:18:33 +0200 Subject: [PATCH 11/55] YEET --- .../Internal/Codegen/CilCodegen.cs | 2 - .../Internal/Codegen/MetadataCodegen.cs | 43 +++---------------- .../OptimizingIr/FunctionBodyCodegen.cs | 10 ++--- .../OptimizingIr/InstructionFactory.cs | 4 +- .../Internal/OptimizingIr/Model/BasicBlock.cs | 3 +- .../Internal/OptimizingIr/Model/Global.cs | 23 ---------- .../OptimizingIr/Model/IBasicBlock.cs | 2 +- .../Internal/OptimizingIr/Model/IProcedure.cs | 20 +++------ .../OptimizingIr/Model/LoadInstruction.cs | 9 ++-- .../Internal/OptimizingIr/Model/Local.cs | 34 --------------- .../Internal/OptimizingIr/Model/Parameter.cs | 27 ------------ .../Internal/OptimizingIr/Model/Procedure.cs | 40 ++++++++--------- .../OptimizingIr/Model/StoreInstruction.cs | 11 ++--- 13 files changed, 49 insertions(+), 179 deletions(-) delete mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/Global.cs delete mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/Local.cs delete mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/Parameter.cs diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 5fbac54d0a..ab042438ea 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -64,8 +64,6 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) this.InstructionEncoder = new InstructionEncoder(codeBuilder, controlFlowBuilder); } - private MemberReferenceHandle GetGlobalReferenceHandle(Global global) => this.metadataCodegen.GetGlobalReferenceHandle(global); - private MemberReferenceHandle GetProcedureDefinitionHandle(IProcedure procedure) => this.metadataCodegen.GetProcedureReferenceHandle(procedure); private UserStringHandle GetStringLiteralHandle(string text) => this.metadataCodegen.GetStringLiteralHandle(text); private EntityHandle GetHandle(Symbol symbol) => this.metadataCodegen.GetEntityHandle(symbol); diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index e66baa29c6..1c834bf545 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -65,8 +65,6 @@ public static void Generate(Compilation compilation, IAssembly assembly, Stream private readonly IAssembly assembly; private readonly BlobBuilder ilBuilder = new(); - private readonly Dictionary globalReferenceHandles = new(); - private readonly Dictionary procedureReferenceHandles = new(); private readonly Dictionary moduleReferenceHandles = new(); private readonly Dictionary intrinsicReferenceHandles = new(); private readonly AssemblyReferenceHandle systemRuntimeReference; @@ -116,35 +114,6 @@ private void WriteModuleAndAssemblyDefinition() methodList: MetadataTokens.MethodDefinitionHandle(1)); } - public MemberReferenceHandle GetGlobalReferenceHandle(Global global) - { - if (!this.globalReferenceHandles.TryGetValue(global, out var handle)) - { - // Add the field reference - handle = this.AddMemberReference( - parent: this.GetModuleReferenceHandle(global.DeclaringModule), - name: global.Name, - signature: this.EncodeGlobalSignature(global)); - // Cache - this.globalReferenceHandles.Add(global, handle); - } - return handle; - } - - public MemberReferenceHandle GetProcedureReferenceHandle(IProcedure procedure) - { - if (!this.procedureReferenceHandles.TryGetValue(procedure, out var handle)) - { - var signature = this.EncodeProcedureSignature(procedure); - handle = this.AddMemberReference( - parent: this.GetModuleReferenceHandle(procedure.DeclaringModule), - name: procedure.Name, - signature: signature); - this.procedureReferenceHandles.Add(procedure, handle); - } - return handle; - } - public TypeReferenceHandle GetModuleReferenceHandle(IModule module) { if (!this.moduleReferenceHandles.TryGetValue(module, out var handle)) @@ -464,14 +433,14 @@ private void EncodeModule(IModule module, TypeDefinitionHandle? parentModule = n } } - private FieldDefinitionHandle EncodeGlobal(Global global) + private FieldDefinitionHandle EncodeGlobal(GlobalSymbol global) { - var visibility = global.Symbol.Visibility switch + var visibility = global.Visibility switch { Api.Semantics.Visibility.Public => FieldAttributes.Public, Api.Semantics.Visibility.Internal => FieldAttributes.Assembly, Api.Semantics.Visibility.Private => FieldAttributes.Private, - _ => throw new ArgumentOutOfRangeException(nameof(global.Symbol.Visibility)), + _ => throw new ArgumentOutOfRangeException(nameof(global.Visibility)), }; // Definition @@ -519,7 +488,7 @@ private MethodDefinitionHandle EncodeProcedure(IProcedure procedure, string? spe // Parameters var parameterList = this.NextParameterHandle; - foreach (var param in procedure.ParametersInDefinitionOrder) + foreach (var param in procedure.Parameters) { this.AddParameterDefinition( attributes: ParameterAttributes.None, @@ -553,7 +522,7 @@ private MethodDefinitionHandle EncodeProcedure(IProcedure procedure, string? spe return definitionHandle; } - private BlobHandle EncodeGlobalSignature(Global global) => + private BlobHandle EncodeGlobalSignature(GlobalSymbol global) => this.EncodeBlob(e => this.EncodeSignatureType(e.Field().Type(), global.Type)); private BlobHandle EncodeProcedureSignature(IProcedure procedure) => this.EncodeBlob(e => @@ -562,7 +531,7 @@ private BlobHandle EncodeProcedureSignature(IProcedure procedure) => this.Encode .MethodSignature(genericParameterCount: procedure.Generics.Count) .Parameters(procedure.Parameters.Count, out var retEncoder, out var paramsEncoder); this.EncodeReturnType(retEncoder, procedure.ReturnType); - foreach (var param in procedure.ParametersInDefinitionOrder) + foreach (var param in procedure.Parameters) { this.EncodeSignatureType(paramsEncoder.AddParameter().Type(), param.Type); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 10eac09e1a..90c6407b0a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -66,9 +66,9 @@ private Module GetDefiningModule(Symbol symbol) private Procedure DefineProcedure(FunctionSymbol function) => this.GetDefiningModule(function).DefineProcedure(function); private BasicBlock DefineBasicBlock(LabelSymbol label) => this.procedure.DefineBasicBlock(label); - private Local DefineLocal(LocalSymbol local) => this.procedure.DefineLocal(local); - private Global DefineGlobal(GlobalSymbol global) => this.GetDefiningModule(global).DefineGlobal(global); - private Parameter DefineParameter(ParameterSymbol param) => this.procedure.DefineParameter(param); + private int DefineLocal(LocalSymbol local) => this.procedure.DefineLocal(local); + private int DefineGlobal(GlobalSymbol global) => this.GetDefiningModule(global).DefineGlobal(global); + private int DefineParameter(ParameterSymbol param) => this.procedure.DefineParameter(param); public Register DefineRegister(TypeSymbol type) => this.procedure.DefineRegister(type); @@ -205,7 +205,7 @@ public override IOperand VisitConditionalGotoStatement(BoundConditionalGotoState var receiver = field.Receiver is null ? null : this.Compile(field.Receiver); if (receiver is null) { - var src = new SymbolReference(field.Field); + var src = field.Field; return (Load: Load(default!, src), Store: Store(src, default!)); } else @@ -547,7 +547,7 @@ public override IOperand VisitFieldExpression(BoundFieldExpression node) var receiver = node.Receiver is null ? null : this.Compile(node.Receiver); var result = this.DefineRegister(node.TypeRequired); this.Write(receiver is null - ? Load(result, new SymbolReference(node.Field)) + ? Load(result, node.Field) : LoadField(result, receiver, node.Field)); return result; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs b/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs index d7208e25aa..907e9429cd 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs @@ -13,12 +13,12 @@ internal static class InstructionFactory public static NopInstruction Nop() => new(); public static BoxInstruction Box(Register target, TypeSymbol boxedType, IOperand value) => new(target, boxedType, value); - public static StoreInstruction Store(IOperand target, IOperand source) => new(target, source); + public static StoreInstruction Store(Symbol target, IOperand source) => new(target, source); public static StoreElementInstruction StoreElement(IOperand array, IEnumerable indices, IOperand source) => new(array, indices, source); public static StoreFieldInstruction StoreField(IOperand receiver, FieldSymbol field, IOperand source) => new(receiver, field, source); - public static LoadInstruction Load(Register target, IOperand source) => new(target, source); + public static LoadInstruction Load(Register target, Symbol source) => new(target, source); public static LoadElementInstruction LoadElement(Register target, IOperand array, IEnumerable indices) => new(target, array, indices); public static LoadFieldInstruction LoadField(Register target, IOperand receiver, FieldSymbol field) => diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BasicBlock.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BasicBlock.cs index 1f4b59ec01..3af8026405 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BasicBlock.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BasicBlock.cs @@ -58,13 +58,12 @@ public BasicBlock(Procedure procedure, LabelSymbol symbol) public override string ToString() { var result = new StringBuilder(); - result.Append(this.ToOperandString()).Append(':'); + result.Append("lbl").Append(this.Index).Append(':'); if (!string.IsNullOrWhiteSpace(this.Symbol.Name)) result.Append($" ; {this.Symbol.Name}"); result.AppendLine(); result.AppendJoin(Environment.NewLine, this.Instructions.Select(i => $" {i}")); return result.ToString(); } - public string ToOperandString() => $"lbl{this.Index}"; private void AssertOwnInstruction(InstructionBase instruction) { diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Global.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Global.cs deleted file mode 100644 index ee6e129406..0000000000 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Global.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Draco.Compiler.Internal.Symbols; - -namespace Draco.Compiler.Internal.OptimizingIr.Model; - -/// -/// A global value that can be read from and written to. -/// -/// The corresponding global symbol. -internal readonly record struct Global(GlobalSymbol Symbol, IModule DeclaringModule) : IOperand -{ - /// - /// An optional name of this global. - /// - public string Name => this.Symbol.Name; - - /// - /// The type this global holds. - /// - public TypeSymbol Type => this.Symbol.Type; - - public override string ToString() => $"global {this.ToOperandString()}: {this.Type}"; - public string ToOperandString() => this.Name; -} diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IBasicBlock.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IBasicBlock.cs index 930ba80142..5608f52563 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IBasicBlock.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IBasicBlock.cs @@ -6,7 +6,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// Read-only interface of a basic-block. /// -internal interface IBasicBlock : IOperand +internal interface IBasicBlock { /// /// The corresponding label. diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs index bce0feb078..a8f6dde993 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs @@ -6,7 +6,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// Read-only interface of a procedure. /// -internal interface IProcedure : IOperand +internal interface IProcedure { /// /// The symbol that corresponds to this procedure. @@ -39,14 +39,9 @@ internal interface IProcedure : IOperand public IReadOnlyList Generics { get; } /// - /// All parameters for this procedure. + /// All parameters for this procedure in the order they were defined. /// - public IReadOnlyDictionary Parameters { get; } - - /// - /// The parameters in the order they were defined. - /// - public IEnumerable ParametersInDefinitionOrder { get; } + public IReadOnlyList Parameters { get; } /// /// The return type of this procedure. @@ -64,14 +59,9 @@ internal interface IProcedure : IOperand public IEnumerable BasicBlocksInDefinitionOrder { get; } /// - /// The locals defined within this procedure. - /// - public IReadOnlyDictionary Locals { get; } - - /// - /// The locals in the order they were defined. + /// The locals defined within this procedure, in definition order. /// - public IEnumerable LocalsInDefinitionOrder { get; } + public IReadOnlyList Locals { get; } /// /// The registers in this procedure. diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs index d29bffe841..26063eb698 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -12,18 +13,16 @@ internal sealed class LoadInstruction : InstructionBase, IValueInstruction /// /// The operand to load from. /// - public IOperand Source { get; set; } + public Symbol Source { get; set; } - public override IEnumerable Operands => new[] { this.Source }; - - public LoadInstruction(Register target, IOperand source) + public LoadInstruction(Register target, Symbol source) { this.Target = target; this.Source = source; } public override string ToString() => - $"{this.Target.ToOperandString()} := load {this.Source.ToOperandString()}"; + $"{this.Target.ToOperandString()} := load {this.Source.FullName}"; public override LoadInstruction Clone() => new(this.Target, this.Source); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Local.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Local.cs deleted file mode 100644 index e88a2ddbb4..0000000000 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Local.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Text; -using Draco.Compiler.Internal.Symbols; - -namespace Draco.Compiler.Internal.OptimizingIr.Model; - -/// -/// A local value that can be read from and written to. -/// -/// The corresponding local symbol. -/// The index of this local to help naming. -internal readonly record struct Local(LocalSymbol Symbol, int Index) : IOperand -{ - /// - /// An optional name of this local. - /// - public string Name => this.Symbol.Name; - - /// - /// The type this local holds. - /// - public TypeSymbol Type => this.Symbol.Type; - - public override string ToString() - { - var result = new StringBuilder(); - result.Append($"{this.ToOperandString()}: {this.Type}"); - if (!string.IsNullOrWhiteSpace(this.Name)) result.Append($" ; {this.Name}"); - return result.ToString(); - } - public string ToOperandString() => $"loc{this.Index}"; - - public bool Equals(Local other) => this.Symbol == other.Symbol; - public override int GetHashCode() => this.Symbol.GetHashCode(); -} diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Parameter.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Parameter.cs deleted file mode 100644 index c3f5beaaa1..0000000000 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Parameter.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Draco.Compiler.Internal.Symbols; - -namespace Draco.Compiler.Internal.OptimizingIr.Model; - -/// -/// A read-only parameter value defined by a procedure. -/// -/// The corresponding parameter symbol. -/// The index of the parameter. -internal readonly record struct Parameter(ParameterSymbol Symbol, int Index) : IOperand -{ - /// - /// An optional name of this parameter. - /// - public string Name => this.Symbol.Name; - - /// - /// The type this parameter holds. - /// - public TypeSymbol Type => this.Symbol.Type; - - public override string ToString() => $"{this.ToOperandString()}: {this.Type}"; - public string ToOperandString() => this.Name; - - public bool Equals(Parameter other) => this.Symbol == other.Symbol; - public override int GetHashCode() => this.Symbol.GetHashCode(); -} diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs index 2cf2a4bf4a..b54fed0cbc 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs @@ -21,20 +21,18 @@ internal sealed class Procedure : IProcedure public BasicBlock Entry { get; } IBasicBlock IProcedure.Entry => this.Entry; public IReadOnlyList Generics => this.Symbol.GenericParameters; - public IReadOnlyDictionary Parameters => this.parameters; - public IEnumerable ParametersInDefinitionOrder => this.parameters.Values.OrderBy(p => p.Index); + public IReadOnlyList Parameters => this.parameters; public TypeSymbol ReturnType => this.Symbol.ReturnType; public IReadOnlyDictionary BasicBlocks => this.basicBlocks; public IEnumerable BasicBlocksInDefinitionOrder => this.basicBlocks.Values .Cast() .OrderBy(bb => bb.Index); - public IReadOnlyDictionary Locals => this.locals; - public IEnumerable LocalsInDefinitionOrder => this.locals.Values.OrderBy(l => l.Index); + public IReadOnlyList Locals => this.locals; public IReadOnlyList Registers => this.registers; - private readonly Dictionary parameters = new(); + private readonly List parameters = new(); private readonly Dictionary basicBlocks = new(); - private readonly Dictionary locals = new(); + private readonly List locals = new(); private readonly List registers = new(); public Procedure(Module declaringModule, FunctionSymbol symbol) @@ -44,14 +42,15 @@ public Procedure(Module declaringModule, FunctionSymbol symbol) this.Entry = this.DefineBasicBlock(new SynthetizedLabelSymbol("begin")); } - public Parameter DefineParameter(ParameterSymbol symbol) + public int DefineParameter(ParameterSymbol symbol) { - if (!this.parameters.TryGetValue(symbol, out var param)) + var index = this.parameters.IndexOf(symbol); + if (index == -1) { - param = new Parameter(symbol, this.parameters.Count); - this.parameters.Add(symbol, param); + index = this.parameters.Count; + this.parameters.Add(symbol); } - return param; + return index; } public BasicBlock DefineBasicBlock(LabelSymbol symbol) @@ -66,14 +65,15 @@ public BasicBlock DefineBasicBlock(LabelSymbol symbol) public bool RemoveBasicBlock(IBasicBlock bb) => this.basicBlocks.Remove(bb.Symbol); - public Local DefineLocal(LocalSymbol symbol) + public int DefineLocal(LocalSymbol symbol) { - if (!this.locals.TryGetValue(symbol, out var result)) + var index = this.locals.IndexOf(symbol); + if (index == -1) { - result = new Local(symbol, this.locals.Count); - this.locals.Add(symbol, result); + index = this.parameters.Count; + this.locals.Add(symbol); } - return result; + return index; } public Register DefineRegister(TypeSymbol type) @@ -86,7 +86,7 @@ public Register DefineRegister(TypeSymbol type) public override string ToString() { var result = new StringBuilder(); - result.Append($"proc {this.ToOperandString()}"); + result.Append($"proc {this.Name}"); if (this.Generics.Count > 0) { result.Append('<'); @@ -94,16 +94,14 @@ public override string ToString() result.Append('>'); } result.Append('('); - result.AppendJoin(", ", this.ParametersInDefinitionOrder); + result.AppendJoin(", ", this.Parameters); result.AppendLine($") {this.ReturnType}:"); if (this.Locals.Count > 0) { result.AppendLine("locals:"); - foreach (var local in this.LocalsInDefinitionOrder) result.AppendLine($" {local}"); + foreach (var local in this.Locals) result.AppendLine($" {local}"); } result.AppendJoin(System.Environment.NewLine, this.BasicBlocksInDefinitionOrder); return result.ToString(); } - - public string ToOperandString() => this.Symbol.Name; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs index 1b0ebb5027..1a6008eba2 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -8,24 +9,24 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; internal sealed class StoreInstruction : InstructionBase { /// - /// The operand to store to. + /// The symbol to store to. /// - public IOperand Target { get; set; } + public Symbol Target { get; set; } /// /// The operand to store the value of. /// public IOperand Source { get; set; } - public override IEnumerable Operands => new[] { this.Target, this.Source }; + public override IEnumerable Operands => new[] { this.Source }; - public StoreInstruction(IOperand target, IOperand source) + public StoreInstruction(Symbol target, IOperand source) { this.Target = target; this.Source = source; } - public override string ToString() => $"store {this.Target.ToOperandString()} := {this.Source.ToOperandString()}"; + public override string ToString() => $"store {this.Target.FullName} := {this.Source.ToOperandString()}"; public override StoreInstruction Clone() => new(this.Target, this.Source); } From 4ac9042d9195e2b55b172795fe3b8979f3d3b1bd Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 08:36:39 +0200 Subject: [PATCH 12/55] Update CilCodegen.cs --- .../Internal/Codegen/CilCodegen.cs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index ab042438ea..06415ced9f 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -9,7 +9,6 @@ using Draco.Compiler.Internal.Symbols; using Draco.Compiler.Internal.Symbols.Synthetized; using Constant = Draco.Compiler.Internal.OptimizingIr.Model.Constant; -using Parameter = Draco.Compiler.Internal.OptimizingIr.Model.Parameter; using Void = Draco.Compiler.Internal.OptimizingIr.Model.Void; namespace Draco.Compiler.Internal.Codegen; @@ -178,12 +177,12 @@ private void EncodeInstruction(IInstruction instruction) // Depends on where we load from switch (load.Source) { - case Local local: + case LocalSymbol local: this.LoadLocal(local); break; - case Global global: + case GlobalSymbol global: this.InstructionEncoder.OpCode(ILOpCode.Ldsfld); - this.InstructionEncoder.Token(this.GetGlobalReferenceHandle(global)); + this.EncodeToken(global); break; default: throw new InvalidOperationException(); @@ -229,14 +228,14 @@ private void EncodeInstruction(IInstruction instruction) { switch (store.Target) { - case Local local: + case LocalSymbol local: this.EncodePush(store.Source); this.StoreLocal(local); break; - case Global global: + case GlobalSymbol global: this.EncodePush(store.Source); this.InstructionEncoder.OpCode(ILOpCode.Stsfld); - this.InstructionEncoder.Token(this.GetGlobalReferenceHandle(global)); + this.EncodeToken(global); break; default: throw new InvalidOperationException(); @@ -374,10 +373,7 @@ private void EncodePush(IOperand operand) case Void: return; case Register r: - this.LoadLocal(r); - break; - case Parameter p: - this.InstructionEncoder.LoadArgument(this.GetParameterIndex(p)); + this.LoadRegister(r); break; case Address a: switch (a.Operand) @@ -415,21 +411,21 @@ private void EncodePush(IOperand operand) } } - private void LoadLocal(Local local) + private void LoadLocal(LocalSymbol local) { var index = this.GetLocalIndex(local); if (index is null) return; this.InstructionEncoder.LoadLocal(index.Value); } - private void LoadLocal(Register register) + private void LoadRegister(Register register) { var index = this.GetRegisterIndex(register); if (index is null) return; this.InstructionEncoder.LoadLocal(index.Value); } - private void StoreLocal(Local local) + private void StoreLocal(LocalSymbol local) { var index = this.GetLocalIndex(local); if (index is null) return; From 79d8dd2ae76cf41abdfdf85cd24629d341d5bfd9 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 08:38:58 +0200 Subject: [PATCH 13/55] YES --- .../Internal/OptimizingIr/Model/IModule.cs | 2 +- .../Internal/OptimizingIr/Model/Module.cs | 22 ++++++------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IModule.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IModule.cs index 6f4a8ab6f6..fe07e6f714 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IModule.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IModule.cs @@ -36,7 +36,7 @@ internal interface IModule /// /// The globals within this module. /// - public IReadOnlyDictionary Globals { get; } + public IReadOnlySet Globals { get; } /// /// The compiled procedures within this module. diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Module.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Module.cs index 02938336df..97b1f941bc 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Module.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/Module.cs @@ -12,17 +12,13 @@ internal sealed class Module : IModule { private static readonly string doubleNewline = $"{Environment.NewLine}{Environment.NewLine}"; - private readonly Dictionary globals = new(); - private readonly Dictionary procedures = new(); - private readonly Dictionary submodules = new(); - public ModuleSymbol Symbol { get; } public string Name => this.Symbol.Name; public IReadOnlyDictionary Submodules => this.submodules; - public IReadOnlyDictionary Globals => this.globals; + public IReadOnlySet Globals => this.globals; public Procedure GlobalInitializer { get; } IProcedure IModule.GlobalInitializer => this.GlobalInitializer; @@ -35,6 +31,10 @@ internal sealed class Module : IModule public Module? Parent { get; } IModule? IModule.Parent => this.Parent; + private readonly HashSet globals = new(); + private readonly Dictionary procedures = new(); + private readonly Dictionary submodules = new(); + public Module(ModuleSymbol symbol, Assembly assembly, Module? Parent) { this.Symbol = symbol; @@ -57,15 +57,7 @@ public ImmutableArray GetProcedures() return result.ToImmutable(); } - public Global DefineGlobal(GlobalSymbol globalSymbol) - { - if (!this.globals.TryGetValue(globalSymbol, out var result)) - { - result = new Global(globalSymbol, this); - this.globals.Add(globalSymbol, result); - } - return result; - } + public void DefineGlobal(GlobalSymbol globalSymbol) => this.globals.Add(globalSymbol); public Procedure DefineProcedure(FunctionSymbol functionSymbol) { @@ -91,7 +83,7 @@ public override string ToString() { var result = new StringBuilder(); result.AppendLine($"module {this.Symbol.Name}"); - result.AppendJoin(Environment.NewLine, this.globals.Values); + result.AppendJoin(Environment.NewLine, this.globals); if (this.globals.Count > 0 && this.procedures.Count > 1) result.Append(doubleNewline); result.AppendJoin(doubleNewline, this.procedures.Values); if (this.procedures.Count > 0 && this.submodules.Count > 0) result.Append(doubleNewline); From c5f1d0bc4053a5911d9b8093bd5065aaf7115059 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 21:45:06 +0200 Subject: [PATCH 14/55] MUHAHAHA --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 4 ++-- src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs | 2 +- .../Internal/OptimizingIr/Model/BranchInstruction.cs | 2 +- .../Internal/OptimizingIr/Model/JumpInstruction.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 06415ced9f..36da2d0107 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -68,7 +68,7 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) private EntityHandle GetHandle(Symbol symbol) => this.metadataCodegen.GetEntityHandle(symbol); // TODO: Parameters don't handle unit yet, it introduces some signature problems - private int GetParameterIndex(Parameter parameter) => parameter.Index; + private int GetParameterIndex(ParameterSymbol parameter) => parameter.Index; private AllocatedLocal? GetAllocatedLocal(IOperand operand) { @@ -81,7 +81,7 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) return local; } - private int? GetLocalIndex(Local local) => this.GetAllocatedLocal(local)?.Index; + private int? GetLocalIndex(LocalSymbol local) => this.GetAllocatedLocal(local)?.Index; private int? GetRegisterIndex(Register register) => this.GetAllocatedLocal(register)?.Index; private LabelHandle GetLabel(IBasicBlock block) diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index 1c834bf545..1c15b48c51 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -377,7 +377,7 @@ private void EncodeModule(IModule module, TypeDefinitionHandle? parentModule = n var currentFieldIndex = fieldIndex; var currentProcIndex = procIndex; // Go through globals - foreach (var global in module.Globals.Values) + foreach (var global in module.Globals) { this.EncodeGlobal(global); currentFieldIndex++; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs index 62e0686045..329a53caef 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs @@ -34,7 +34,7 @@ public BranchInstruction(IOperand condition, BasicBlock then, BasicBlock @else) } public override string ToString() => - $"if {this.Condition.ToOperandString()} jump {this.Then.ToOperandString()} else jump {this.Else.ToOperandString()}"; + $"if {this.Condition.ToOperandString()} jump lbl{this.Then.Index} else jump lbl{this.Else.Index}"; public override BranchInstruction Clone() => new(this.Condition, this.Then, this.Else); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs index 37bc110ffe..c8285c385c 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs @@ -21,7 +21,7 @@ public JumpInstruction(BasicBlock target) this.Target = target; } - public override string ToString() => $"jump {this.Target.ToOperandString()}"; + public override string ToString() => $"jump lbl{this.Target.Index}"; public override JumpInstruction Clone() => new(this.Target); } From ff9a0836da514b2929d5ca9b9ed4f3f7b1b203ce Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 21:59:35 +0200 Subject: [PATCH 15/55] YES, YES! --- .../OptimizingIr/FunctionBodyCodegen.cs | 44 +++++++++---------- .../Internal/OptimizingIr/ModuleCodegen.cs | 6 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 90c6407b0a..e186f899e0 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -67,9 +67,6 @@ private Module GetDefiningModule(Symbol symbol) private Procedure DefineProcedure(FunctionSymbol function) => this.GetDefiningModule(function).DefineProcedure(function); private BasicBlock DefineBasicBlock(LabelSymbol label) => this.procedure.DefineBasicBlock(label); private int DefineLocal(LocalSymbol local) => this.procedure.DefineLocal(local); - private int DefineGlobal(GlobalSymbol global) => this.GetDefiningModule(global).DefineGlobal(global); - private int DefineParameter(ParameterSymbol param) => this.procedure.DefineParameter(param); - public Register DefineRegister(TypeSymbol type) => this.procedure.DefineRegister(type); private Procedure SynthetizeProcedure(SynthetizedFunctionSymbol func) @@ -145,8 +142,7 @@ public override IOperand VisitLocalDeclaration(BoundLocalDeclaration node) var right = this.Compile(node.Value); right = this.BoxIfNeeded(node.Local.Type, right); - var left = this.DefineLocal(node.Local); - this.Write(Store(left, right)); + this.Write(Store(node.Local, right)); return default!; } @@ -192,13 +188,11 @@ public override IOperand VisitConditionalGotoStatement(BoundConditionalGotoState { case BoundLocalLvalue local: { - var src = this.DefineLocal(local.Local); - return (Load: Load(default!, src), Store: Store(src, default!)); + return (Load: Load(default!, local.Local), Store: Store(local.Local, default!)); } case BoundGlobalLvalue global: { - var src = this.DefineGlobal(global.Global); - return (Load: Load(default!, src), Store: Store(src, default!)); + return (Load: Load(default!, global.Global), Store: Store(global.Global, default!)); } case BoundFieldLvalue field: { @@ -235,19 +229,22 @@ private IOperand CompileToAddress(BoundExpression expression) { case BoundLocalExpression local: { - var localOperand = this.DefineLocal(local.Local); - return new Address(localOperand); + // TODO + // return new Address(localOperand); + // TODO + throw new System.NotImplementedException(); } default: { // We allocate a local so we can take its address var local = new SynthetizedLocalSymbol(expression.TypeRequired, false); - var localOperand = this.DefineLocal(local); // Store the value in it var value = this.Compile(expression); - this.Write(Store(localOperand, value)); + this.Write(Store(local, value)); // Take its address - return new Address(localOperand); + // return new Address(localOperand); + // TODO + throw new System.NotImplementedException(); } } } @@ -358,6 +355,8 @@ public override IOperand VisitBlockExpression(BoundBlockExpression node) var locals = node.Locals .OfType() .ToList(); + // Register them + foreach (var local in locals) this.DefineLocal(local); // Start scope if (locals.Count > 0) this.Write(StartScope(locals)); @@ -489,16 +488,21 @@ public override IOperand VisitReturnExpression(BoundReturnExpression node) public override IOperand VisitGlobalExpression(BoundGlobalExpression node) { var result = this.DefineRegister(node.TypeRequired); - var global = this.DefineGlobal(node.Global); - this.Write(Load(result, global)); + this.Write(Load(result, node.Global)); return result; } public override IOperand VisitLocalExpression(BoundLocalExpression node) { var result = this.DefineRegister(node.TypeRequired); - var local = this.DefineLocal(node.Local); - this.Write(Load(result, local)); + this.Write(Load(result, node.Local)); + return result; + } + + public override IOperand VisitParameterExpression(BoundParameterExpression node) + { + var result = this.DefineRegister(node.TypeRequired); + this.Write(Load(result, node.Parameter)); return result; } @@ -522,10 +526,6 @@ private FunctionInstanceSymbol TranslateFunctionInstanceSymbol(FunctionInstanceS return i; } - // NOTE: Parameters don't need loading, they are read-only values by default - public override IOperand VisitParameterExpression(BoundParameterExpression node) => - this.DefineParameter(node.Parameter); - public override IOperand VisitLiteralExpression(BoundLiteralExpression node) => new Constant(node.Value, node.TypeRequired); public override IOperand VisitUnitExpression(BoundUnitExpression node) => default(Void); diff --git a/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs index e3912f78a5..ae4e887ab9 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs @@ -38,7 +38,7 @@ public override void VisitGlobal(GlobalSymbol globalSymbol) { if (globalSymbol is not SourceGlobalSymbol sourceGlobal) return; - var global = this.module.DefineGlobal(sourceGlobal); + this.module.DefineGlobal(sourceGlobal); // If there's a value, compile it if (sourceGlobal.Value is not null) @@ -49,8 +49,8 @@ public override void VisitGlobal(GlobalSymbol globalSymbol) // Compile it var value = bodyWithoutLocalFunctions.Accept(this.globalInitializer); // Store it - value = this.globalInitializer.BoxIfNeeded(global.Type, value); - this.globalInitializer.Write(Store(global, value)); + value = this.globalInitializer.BoxIfNeeded(sourceGlobal.Type, value); + this.globalInitializer.Write(Store(sourceGlobal, value)); // Compile the local functions foreach (var localFunc in localFunctions) this.VisitFunction(localFunc); From afc35c4b2ccdff9a7395898e7d1481abe78785b2 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:03:52 +0200 Subject: [PATCH 16/55] One less faulty file --- src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs | 2 +- .../Internal/OptimizingIr/Model/IProcedure.cs | 7 +++++++ .../Internal/OptimizingIr/Model/Procedure.cs | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index 1c15b48c51..e54975fc18 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -493,7 +493,7 @@ private MethodDefinitionHandle EncodeProcedure(IProcedure procedure, string? spe this.AddParameterDefinition( attributes: ParameterAttributes.None, name: param.Name, - index: param.Index); + index: procedure.GetParameterIndex(param)); } // Add definition diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs index a8f6dde993..9e263f7685 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IProcedure.cs @@ -67,4 +67,11 @@ internal interface IProcedure /// The registers in this procedure. /// public IReadOnlyList Registers { get; } + + /// + /// Retrieves the index of the given parameter. + /// + /// The parameter symbol to get the index of. + /// The (0-based) index of the parameter. + public int GetParameterIndex(ParameterSymbol symbol); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs index b54fed0cbc..0598fd279a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs @@ -42,6 +42,13 @@ public Procedure(Module declaringModule, FunctionSymbol symbol) this.Entry = this.DefineBasicBlock(new SynthetizedLabelSymbol("begin")); } + public int GetParameterIndex(ParameterSymbol symbol) + { + var idx = this.parameters.IndexOf(symbol); + if (idx == -1) throw new System.ArgumentOutOfRangeException(nameof(symbol)); + return idx; + } + public int DefineParameter(ParameterSymbol symbol) { var index = this.parameters.IndexOf(symbol); From c5f472f1a191164256f11a04373536e21040b9ec Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:04:45 +0200 Subject: [PATCH 17/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 36da2d0107..ca514b9e11 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -68,7 +68,7 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) private EntityHandle GetHandle(Symbol symbol) => this.metadataCodegen.GetEntityHandle(symbol); // TODO: Parameters don't handle unit yet, it introduces some signature problems - private int GetParameterIndex(ParameterSymbol parameter) => parameter.Index; + private int GetParameterIndex(ParameterSymbol parameter) => this.procedure.GetParameterIndex(parameter); private AllocatedLocal? GetAllocatedLocal(IOperand operand) { @@ -378,6 +378,8 @@ private void EncodePush(IOperand operand) case Address a: switch (a.Operand) { + // TODO + /* case Local local: { var index = this.GetLocalIndex(local); @@ -385,6 +387,7 @@ private void EncodePush(IOperand operand) this.InstructionEncoder.LoadLocalAddress(index.Value); break; } + */ default: throw new NotImplementedException(); } From aa81e4a194385350d2d904226461966ed71e2d1e Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:13:45 +0200 Subject: [PATCH 18/55] WE COMPILE --- .../Internal/Codegen/AllocatedLocal.cs | 12 +----- .../Internal/Codegen/CilCodegen.cs | 37 +++++++++++-------- .../Internal/Codegen/MetadataCodegen.cs | 3 +- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs b/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs index f8f4cd8eca..394227883f 100644 --- a/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs +++ b/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs @@ -6,14 +6,6 @@ namespace Draco.Compiler.Internal.Codegen; /// /// Some method-local variable allocation. /// -/// The corresponding IR operand. +/// The corresponding local symbol. /// The index of the local within the method. -internal readonly record struct AllocatedLocal( - IOperand Operand, - int Index) -{ - /// - /// The symbol associated with this local, if any. - /// - public LocalSymbol? Symbol => this.Operand is Local local ? local.Symbol : null; -} +internal readonly record struct AllocatedLocal(LocalSymbol Symbol, int Index); diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index ca514b9e11..be592ddabc 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -34,8 +34,9 @@ internal sealed class CilCodegen private readonly MetadataCodegen metadataCodegen; private readonly IProcedure procedure; + private readonly Dictionary allocatedLocals; private readonly Dictionary labels = new(); - private readonly Dictionary allocatedLocals = new(); + private readonly Dictionary allocatedRegisters = new(); // NOTE: The current stackification attempt is FLAWED // Imagine this situation: @@ -61,6 +62,11 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) var codeBuilder = new BlobBuilder(); var controlFlowBuilder = new ControlFlowBuilder(); this.InstructionEncoder = new InstructionEncoder(codeBuilder, controlFlowBuilder); + + this.allocatedLocals = procedure.Locals + .Where(local => !SymbolEqualityComparer.Default.Equals(local.Type, IntrinsicSymbols.Unit)) + .Select((local, index) => (Local: local, Index: index)) + .ToDictionary(pair => pair.Local, pair => new AllocatedLocal(pair.Local, pair.Index)); } private UserStringHandle GetStringLiteralHandle(string text) => this.metadataCodegen.GetStringLiteralHandle(text); @@ -70,19 +76,24 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) // TODO: Parameters don't handle unit yet, it introduces some signature problems private int GetParameterIndex(ParameterSymbol parameter) => this.procedure.GetParameterIndex(parameter); - private AllocatedLocal? GetAllocatedLocal(IOperand operand) + private AllocatedLocal? GetAllocatedLocal(LocalSymbol local) { - if (SymbolEqualityComparer.Default.Equals(operand.Type, IntrinsicSymbols.Unit)) return null; - if (!this.allocatedLocals.TryGetValue(operand, out var local)) - { - local = new(operand, this.allocatedLocals.Count); - this.allocatedLocals.Add(operand, local); - } - return local; + if (!this.allocatedLocals.TryGetValue(local, out var allocatedLocal)) return null; + return allocatedLocal; } private int? GetLocalIndex(LocalSymbol local) => this.GetAllocatedLocal(local)?.Index; - private int? GetRegisterIndex(Register register) => this.GetAllocatedLocal(register)?.Index; + private int? GetRegisterIndex(Register register) + { + // We don't allocate registers to void + if (SymbolEqualityComparer.Default.Equals(register.Type, IntrinsicSymbols.Unit)) return null; + if (!this.allocatedRegisters.TryGetValue(register, out var index)) + { + index = this.allocatedRegisters.Count; + this.allocatedRegisters.Add(register, index); + } + return index; + } private LabelHandle GetLabel(IBasicBlock block) { @@ -116,11 +127,7 @@ private void EncodeInstruction(IInstruction instruction) } case StartScope start: { - var localIndices = start.Locals - .Select(sym => this.procedure.Locals[sym]) - .Select(loc => this.GetAllocatedLocal(loc)) - .OfType(); - this.PdbCodegen?.StartScope(this.InstructionEncoder.Offset, localIndices); + this.PdbCodegen?.StartScope(this.InstructionEncoder.Offset, this.allocatedLocals.Values); break; } case EndScope: diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index e54975fc18..05b0be826b 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -547,8 +547,7 @@ private StandaloneSignatureHandle EncodeLocals(ImmutableArray lo foreach (var local in locals) { var typeEncoder = localsEncoder.AddVariable().Type(); - Debug.Assert(local.Operand.Type is not null); - this.EncodeSignatureType(typeEncoder, local.Operand.Type); + this.EncodeSignatureType(typeEncoder, local.Symbol.Type); } })); } From b0b92c65f6f9a6062e56c97ea292933c0746a7bf Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:18:17 +0200 Subject: [PATCH 19/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index be592ddabc..891191f05f 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -127,6 +127,9 @@ private void EncodeInstruction(IInstruction instruction) } case StartScope start: { + var localIndices = start.Locals + .Select(sym => this.GetAllocatedLocal(sym)) + .OfType(); this.PdbCodegen?.StartScope(this.InstructionEncoder.Offset, this.allocatedLocals.Values); break; } From c5cf50af38ab73c55f5147b9f80cab601ae36412 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:36:00 +0200 Subject: [PATCH 20/55] Lots of fixes --- .../Internal/Codegen/CilCodegen.cs | 22 ++++++++++++++++++- .../Internal/Codegen/MetadataCodegen.cs | 14 +++++++++--- .../OptimizingIr/FunctionBodyCodegen.cs | 7 +++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 891191f05f..0974f41ef8 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -30,6 +30,13 @@ internal sealed class CilCodegen .OrderBy(kv => kv.Value.Index) .Select(kv => kv.Value); + /// + /// The allocated registers in order. + /// + public IEnumerable AllocatedRegisters => this.allocatedRegisters + .OrderBy(kv => kv.Value) + .Select(kv => kv.Key); + private PdbCodegen? PdbCodegen => this.metadataCodegen.PdbCodegen; private readonly MetadataCodegen metadataCodegen; @@ -89,7 +96,8 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) if (SymbolEqualityComparer.Default.Equals(register.Type, IntrinsicSymbols.Unit)) return null; if (!this.allocatedRegisters.TryGetValue(register, out var index)) { - index = this.allocatedRegisters.Count; + // IMPORTANT: We need to offset by the locals count + index = this.allocatedLocals.Count + this.allocatedRegisters.Count; this.allocatedRegisters.Add(register, index); } return index; @@ -187,13 +195,23 @@ private void EncodeInstruction(IInstruction instruction) // Depends on where we load from switch (load.Source) { + case ParameterSymbol param: + { + var index = this.GetParameterIndex(param); + this.InstructionEncoder.LoadArgument(index); + break; + } case LocalSymbol local: + { this.LoadLocal(local); break; + } case GlobalSymbol global: + { this.InstructionEncoder.OpCode(ILOpCode.Ldsfld); this.EncodeToken(global); break; + } default: throw new InvalidOperationException(); } @@ -238,6 +256,8 @@ private void EncodeInstruction(IInstruction instruction) { switch (store.Target) { + case ParameterSymbol: + throw new InvalidOperationException(); case LocalSymbol local: this.EncodePush(store.Source); this.StoreLocal(local); diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index 05b0be826b..3c82231e37 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -466,7 +466,8 @@ private MethodDefinitionHandle EncodeProcedure(IProcedure procedure, string? spe // Encode locals var allocatedLocals = cilCodegen.AllocatedLocals.ToImmutableArray(); - var localsHandle = this.EncodeLocals(allocatedLocals); + var allocatedRegisters = cilCodegen.AllocatedRegisters.ToImmutableArray(); + var localsHandle = this.EncodeLocals(allocatedLocals, allocatedRegisters); // Encode body this.ilBuilder.Align(4); @@ -537,18 +538,25 @@ private BlobHandle EncodeProcedureSignature(IProcedure procedure) => this.Encode } }); - private StandaloneSignatureHandle EncodeLocals(ImmutableArray locals) + private StandaloneSignatureHandle EncodeLocals( + ImmutableArray locals, + ImmutableArray registers) { // We must not encode 0 locals if (locals.Length == 0) return default; return this.MetadataBuilder.AddStandaloneSignature(this.EncodeBlob(e => { - var localsEncoder = e.LocalVariableSignature(locals.Length); + var localsEncoder = e.LocalVariableSignature(locals.Length + registers.Length); foreach (var local in locals) { var typeEncoder = localsEncoder.AddVariable().Type(); this.EncodeSignatureType(typeEncoder, local.Symbol.Type); } + foreach (var register in registers) + { + var typeEncoder = localsEncoder.AddVariable().Type(); + this.EncodeSignatureType(typeEncoder, register.Type); + } })); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index e186f899e0..7c6792a6c0 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -351,12 +351,13 @@ public override IOperand VisitGotoExpression(BoundGotoExpression node) public override IOperand VisitBlockExpression(BoundBlockExpression node) { - // Find locals that we care about + // Define all locals + foreach (var local in node.Locals) this.DefineLocal(local); + + // Find locals that we care about for visible scope var locals = node.Locals .OfType() .ToList(); - // Register them - foreach (var local in locals) this.DefineLocal(local); // Start scope if (locals.Count > 0) this.Write(StartScope(locals)); From 68ce7de54324372480bf0e8955856dabdd430f24 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:43:58 +0200 Subject: [PATCH 21/55] Fix --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 2 +- src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 0974f41ef8..e05f12ce59 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -42,8 +42,8 @@ internal sealed class CilCodegen private readonly MetadataCodegen metadataCodegen; private readonly IProcedure procedure; private readonly Dictionary allocatedLocals; - private readonly Dictionary labels = new(); private readonly Dictionary allocatedRegisters = new(); + private readonly Dictionary labels = new(); // NOTE: The current stackification attempt is FLAWED // Imagine this situation: diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index 3c82231e37..b9ed378574 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -543,7 +543,7 @@ private StandaloneSignatureHandle EncodeLocals( ImmutableArray registers) { // We must not encode 0 locals - if (locals.Length == 0) return default; + if (locals.Length + registers.Length == 0) return default; return this.MetadataBuilder.AddStandaloneSignature(this.EncodeBlob(e => { var localsEncoder = e.LocalVariableSignature(locals.Length + registers.Length); From 90369b1811b1df41589a7e6ab22f415c420bc567 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:47:01 +0200 Subject: [PATCH 22/55] Update CilCodegen.cs --- .../Internal/Codegen/CilCodegen.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index e05f12ce59..bd38e1ef03 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -41,8 +41,8 @@ internal sealed class CilCodegen private readonly MetadataCodegen metadataCodegen; private readonly IProcedure procedure; - private readonly Dictionary allocatedLocals; - private readonly Dictionary allocatedRegisters = new(); + private readonly ImmutableDictionary allocatedLocals; + private readonly ImmutableDictionary allocatedRegisters; private readonly Dictionary labels = new(); // NOTE: The current stackification attempt is FLAWED @@ -73,7 +73,11 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) this.allocatedLocals = procedure.Locals .Where(local => !SymbolEqualityComparer.Default.Equals(local.Type, IntrinsicSymbols.Unit)) .Select((local, index) => (Local: local, Index: index)) - .ToDictionary(pair => pair.Local, pair => new AllocatedLocal(pair.Local, pair.Index)); + .ToImmutableDictionary(pair => pair.Local, pair => new AllocatedLocal(pair.Local, pair.Index)); + this.allocatedRegisters = procedure.Registers + .Where(reg => !SymbolEqualityComparer.Default.Equals(reg.Type, IntrinsicSymbols.Unit)) + .Select((local, index) => (Local: local, Index: index)) + .ToImmutableDictionary(pair => pair.Local, pair => this.allocatedLocals.Count + pair.Index); } private UserStringHandle GetStringLiteralHandle(string text) => this.metadataCodegen.GetStringLiteralHandle(text); @@ -92,15 +96,8 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) private int? GetLocalIndex(LocalSymbol local) => this.GetAllocatedLocal(local)?.Index; private int? GetRegisterIndex(Register register) { - // We don't allocate registers to void - if (SymbolEqualityComparer.Default.Equals(register.Type, IntrinsicSymbols.Unit)) return null; - if (!this.allocatedRegisters.TryGetValue(register, out var index)) - { - // IMPORTANT: We need to offset by the locals count - index = this.allocatedLocals.Count + this.allocatedRegisters.Count; - this.allocatedRegisters.Add(register, index); - } - return index; + if (!this.allocatedRegisters.TryGetValue(register, out var allocatedRegister)) return null; + return allocatedRegister; } private LabelHandle GetLabel(IBasicBlock block) From e7e1f87df4acfd47c3b91a9dee205a90a5d4824f Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:52:09 +0200 Subject: [PATCH 23/55] Update MetadataCodegen.cs --- .../Internal/Codegen/MetadataCodegen.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index b9ed378574..d0a02bbd5a 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -254,6 +254,19 @@ public EntityHandle GetEntityHandle(Symbol symbol) })); } + case GlobalSymbol global: + { + return this.AddMemberReference( + parent: this.GetEntityHandle(global.ContainingSymbol + ?? throw new InvalidOperationException()), + name: global.Name, + signature: this.EncodeBlob(e => + { + var encoder = e.Field(); + this.EncodeSignatureType(encoder.Type(), global.Type); + })); + } + default: throw new ArgumentOutOfRangeException(nameof(symbol)); } From c62f761f06e017a56c35213a1c5d4f9d40248d71 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Mon, 9 Oct 2023 22:59:11 +0200 Subject: [PATCH 24/55] Update FunctionBodyCodegen.cs --- .../Internal/OptimizingIr/FunctionBodyCodegen.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 7c6792a6c0..90d1d13b29 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -79,6 +79,10 @@ private Procedure SynthetizeProcedure(SynthetizedFunctionSymbol func) { var codegen = new FunctionBodyCodegen(this.compilation, proc); func.Body.Accept(codegen); + // TODO: Kinda duplication + // Maybe we should move parameter definition to the proc construction simply? + // Or even simpler, just project from symbol? + foreach (var param in func.Parameters) proc.DefineParameter(param); } return proc; } From 8c5c4eb88d7d23195a12065618ab9a644a65bcdf Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Tue, 10 Oct 2023 09:59:00 +0200 Subject: [PATCH 25/55] No less errors, but no crash --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 15 +++++++++++++++ .../Symbols/Metadata/MetadataFieldSymbol.cs | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index bd38e1ef03..7c7618e062 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -209,6 +210,14 @@ private void EncodeInstruction(IInstruction instruction) this.EncodeToken(global); break; } + // TODO: REALLY MERGE static fields with globals! + case FieldSymbol field: + { + Debug.Assert(field.IsStatic); + this.InstructionEncoder.OpCode(ILOpCode.Ldsfld); + this.EncodeToken(field); + break; + } default: throw new InvalidOperationException(); } @@ -264,6 +273,12 @@ private void EncodeInstruction(IInstruction instruction) this.InstructionEncoder.OpCode(ILOpCode.Stsfld); this.EncodeToken(global); break; + // TODO: REALLY MERGE static fields with globals! + case FieldSymbol field: + Debug.Assert(field.IsStatic); + this.InstructionEncoder.OpCode(ILOpCode.Stsfld); + this.EncodeToken(field); + break; default: throw new InvalidOperationException(); } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs index 7e03e1d054..0f15dddf1e 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs @@ -6,6 +6,8 @@ namespace Draco.Compiler.Internal.Symbols.Metadata; +// TODO: For static ones, we could just merge them with globals... + /// /// Fields read from metadata. /// From 90ad539f9bf3164f87e2c39fc7e2025813bcf31e Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Tue, 10 Oct 2023 10:27:47 +0200 Subject: [PATCH 26/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 7c7618e062..ea44d553ab 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -276,6 +276,7 @@ private void EncodeInstruction(IInstruction instruction) // TODO: REALLY MERGE static fields with globals! case FieldSymbol field: Debug.Assert(field.IsStatic); + this.EncodePush(store.Source); this.InstructionEncoder.OpCode(ILOpCode.Stsfld); this.EncodeToken(field); break; From 5f871a74c626ba5d926f621a375753bbaba52217 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Tue, 10 Oct 2023 15:36:37 +0200 Subject: [PATCH 27/55] Split out static fields --- .../Semantics/SymbolResolutionTests.cs | 8 +- .../Semantics/TypeCheckingTests.cs | 2 +- .../Internal/Binding/Binder_UntypedLvalue.cs | 2 + .../OptimizingIr/FunctionBodyCodegen.cs | 20 ++++ .../Internal/Symbols/FieldSymbol.cs | 4 +- .../Symbols/Generic/FieldInstanceSymbol.cs | 2 - .../Symbols/Metadata/MetadataFieldSymbol.cs | 11 +- .../Metadata/MetadataStaticClassSymbol.cs | 2 +- .../Metadata/MetadataStaticFieldSymbol.cs | 103 ++++++++++++++++++ .../Symbols/Metadata/MetadataTypeSymbol.cs | 6 +- 10 files changed, 142 insertions(+), 18 deletions(-) create mode 100644 src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs diff --git a/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs b/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs index 1c0e0c8cab..f259bc1e1f 100644 --- a/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs +++ b/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs @@ -1807,7 +1807,7 @@ public static class FooModule{ var diags = semanticModel.Diagnostics; var xSym = GetInternalSymbol(semanticModel.GetDeclaredSymbol(xDecl)); - var fooSym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(fooModuleRef)), "foo"); + var fooSym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(fooModuleRef)), "foo"); var fooDecl = GetMetadataSymbol(compilation, null, "FooModule", "foo"); // Assert @@ -1857,7 +1857,7 @@ public static class FooModule{ var diags = semanticModel.Diagnostics; var xSym = GetInternalSymbol(semanticModel.GetDeclaredSymbol(xDecl)); - var fooSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(fooNameRef)); + var fooSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(fooNameRef)); var fooDecl = GetMetadataSymbol(compilation, null, "FooModule", "foo"); // Assert @@ -1951,7 +1951,7 @@ public static class FooModule{ var semanticModel = compilation.GetSemanticModel(main); var diags = semanticModel.Diagnostics; - var fooSym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(fooModuleRef)), "foo"); + var fooSym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(fooModuleRef)), "foo"); var fooDecl = GetMetadataSymbol(compilation, null, "FooModule", "foo"); // Assert @@ -1996,7 +1996,7 @@ public static class FooModule{ var semanticModel = compilation.GetSemanticModel(main); var diags = semanticModel.Diagnostics; - var fooSym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(fooModuleRef)), "foo"); + var fooSym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(fooModuleRef)), "foo"); var fooDecl = GetMetadataSymbol(compilation, null, "FooModule", "foo"); // Assert diff --git a/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs b/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs index 9ba838701d..8fd15c8bd4 100644 --- a/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs +++ b/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs @@ -1075,7 +1075,7 @@ public void AccessingField() var semanticModel = compilation.GetSemanticModel(tree); var xSym = GetInternalSymbol(semanticModel.GetDeclaredSymbol(xDecl)); - var stringEmptySym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(consoleRef)), "Empty"); + var stringEmptySym = GetMemberSymbol(GetInternalSymbol(semanticModel.GetReferencedSymbol(consoleRef)), "Empty"); // Assert Assert.Empty(semanticModel.Diagnostics); diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs index 3d6509abd8..827b256508 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs @@ -147,6 +147,8 @@ private UntypedLvalue SymbolToLvalue(SyntaxNode syntax, Symbol symbol, Constrain { switch (symbol) { + case GlobalSymbol global: + return new UntypedGlobalLvalue(syntax, global); case FieldSymbol field: return new UntypedFieldLvalue(syntax, null, field); case PropertySymbol prop: diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 90d1d13b29..712445d2fe 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -492,6 +492,19 @@ public override IOperand VisitReturnExpression(BoundReturnExpression node) public override IOperand VisitGlobalExpression(BoundGlobalExpression node) { + // Check, if constant literal that has to be inlined + var metadataGlobal = ExtractMetadataStaticField(node.Global); + if (metadataGlobal is not null && metadataGlobal.IsLiteral) + { + var defaultValue = metadataGlobal.DefaultValue; + if (!BinderFacts.TryGetLiteralType(defaultValue, this.compilation.IntrinsicSymbols, out var literalType)) + { + throw new System.InvalidOperationException(); + } + return new Constant(defaultValue, literalType); + } + + // Regular global var result = this.DefineRegister(node.TypeRequired); this.Write(Load(result, node.Global)); return result; @@ -563,4 +576,11 @@ public override IOperand VisitFieldExpression(BoundFieldExpression node) FieldInstanceSymbol i => ExtractMetadataField(i.GenericDefinition), _ => null, }; + + private static MetadataStaticFieldSymbol? ExtractMetadataStaticField(GlobalSymbol global) => global switch + { + MetadataStaticFieldSymbol m => m, + // TODO: Global instances? + _ => null, + }; } diff --git a/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs index 95aa990032..22a0072fea 100644 --- a/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs @@ -5,11 +5,11 @@ namespace Draco.Compiler.Internal.Symbols; /// -/// Represents a field. +/// Represents a nonstatic field. /// internal abstract class FieldSymbol : VariableSymbol, IMemberSymbol { - public abstract bool IsStatic { get; } + public bool IsStatic => false; public override FieldSymbol GenericInstantiate(Symbol? containingSymbol, ImmutableArray arguments) => (FieldSymbol)base.GenericInstantiate(containingSymbol, arguments); diff --git a/src/Draco.Compiler/Internal/Symbols/Generic/FieldInstanceSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Generic/FieldInstanceSymbol.cs index 93e50e28cf..75e92131e4 100644 --- a/src/Draco.Compiler/Internal/Symbols/Generic/FieldInstanceSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Generic/FieldInstanceSymbol.cs @@ -13,8 +13,6 @@ internal sealed class FieldInstanceSymbol : FieldSymbol, IGenericInstanceSymbol public override bool IsMutable => this.GenericDefinition.IsMutable; - public override bool IsStatic => this.GenericDefinition.IsStatic; - public override Symbol? ContainingSymbol { get; } public override FieldSymbol GenericDefinition { get; } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs index 0f15dddf1e..f7d53ebeb2 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs @@ -6,10 +6,8 @@ namespace Draco.Compiler.Internal.Symbols.Metadata; -// TODO: For static ones, we could just merge them with globals... - /// -/// Fields read from metadata. +/// Nonstatic fields read from metadata. /// internal sealed class MetadataFieldSymbol : FieldSymbol, IMetadataSymbol { @@ -18,8 +16,6 @@ internal sealed class MetadataFieldSymbol : FieldSymbol, IMetadataSymbol public override bool IsMutable => !(this.fieldDefinition.Attributes.HasFlag(FieldAttributes.Literal) || this.fieldDefinition.Attributes.HasFlag(FieldAttributes.InitOnly)); - public override bool IsStatic => this.fieldDefinition.Attributes.HasFlag(FieldAttributes.Static); - public override string Name => this.MetadataReader.GetString(this.fieldDefinition.Name); public override Api.Semantics.Visibility Visibility @@ -75,6 +71,11 @@ public override Api.Semantics.Visibility Visibility public MetadataFieldSymbol(Symbol containingSymbol, FieldDefinition fieldDefinition) { + if (fieldDefinition.Attributes.HasFlag(FieldAttributes.Static)) + { + throw new System.ArgumentException("fields must be constructed from nonstatic fields"); + } + this.ContainingSymbol = containingSymbol; this.fieldDefinition = fieldDefinition; } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs index ffb73d1318..3014fb2e0e 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs @@ -91,7 +91,7 @@ private ImmutableArray BuildMembers() if (!fieldDef.Attributes.HasFlag(FieldAttributes.Public)) continue; // Skip non-static fields if (!fieldDef.Attributes.HasFlag(FieldAttributes.Static)) continue; - var fieldSym = new MetadataFieldSymbol( + var fieldSym = new MetadataStaticFieldSymbol( containingSymbol: this, fieldDefinition: fieldDef); result.Add(fieldSym); diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs new file mode 100644 index 0000000000..61e670046d --- /dev/null +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs @@ -0,0 +1,103 @@ +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; + +namespace Draco.Compiler.Internal.Symbols.Metadata; + +// TODO: Copypasta from metadata field + +/// +/// Static fields read from metadata. +/// +internal sealed class MetadataStaticFieldSymbol : GlobalSymbol, IMetadataSymbol +{ + public override TypeSymbol Type => InterlockedUtils.InitializeNull(ref this.type, this.BuildType); + private TypeSymbol? type; + + public override bool IsMutable => !(this.fieldDefinition.Attributes.HasFlag(FieldAttributes.Literal) || this.fieldDefinition.Attributes.HasFlag(FieldAttributes.InitOnly)); + + public override string Name => this.MetadataReader.GetString(this.fieldDefinition.Name); + + public override Api.Semantics.Visibility Visibility + { + get + { + // If this is an interface member, default to public + if (this.ContainingSymbol is TypeSymbol { IsInterface: true }) + { + return Api.Semantics.Visibility.Public; + } + + // Otherwise read flag from metadata + return this.fieldDefinition.Attributes.HasFlag(FieldAttributes.Public) + ? Api.Semantics.Visibility.Public + : Api.Semantics.Visibility.Internal; + } + } + + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => InterlockedUtils.InitializeNull(ref this.rawDocumentation, this.BuildRawDocumentation); + private string? rawDocumentation; + + public override Symbol? ContainingSymbol { get; } + + /// + /// The metadata assembly of this metadata symbol. + /// + // NOTE: thread-safety does not matter, same instance + public MetadataAssemblySymbol Assembly => this.assembly ??= this.AncestorChain.OfType().First(); + private MetadataAssemblySymbol? assembly; + + /// + /// The metadata reader that was used to read up this metadata symbol. + /// + public MetadataReader MetadataReader => this.Assembly.MetadataReader; + + /// + /// True, if this is a literal that cannot be referenced as a field, but needs to be inlined as a value. + /// This is the case for enum members. + /// + public bool IsLiteral => this.fieldDefinition.Attributes.HasFlag(FieldAttributes.Literal); + + /// + /// The default value of this field. + /// + public object? DefaultValue => InterlockedUtils.InitializeMaybeNull(ref this.defaultValue, this.BuildDefaultValue); + private object? defaultValue; + + private readonly FieldDefinition fieldDefinition; + + public MetadataStaticFieldSymbol(Symbol containingSymbol, FieldDefinition fieldDefinition) + { + if (!fieldDefinition.Attributes.HasFlag(FieldAttributes.Static)) + { + throw new System.ArgumentException("globals must be constructed from static fields"); + } + + this.ContainingSymbol = containingSymbol; + this.fieldDefinition = fieldDefinition; + } + + private TypeSymbol BuildType() => + this.fieldDefinition.DecodeSignature(this.Assembly.Compilation.TypeProvider, this); + + private object? BuildDefaultValue() + { + var constantHandle = this.fieldDefinition.GetDefaultValue(); + if (constantHandle.IsNil) return null; + + var constant = this.MetadataReader.GetConstant(constantHandle); + return MetadataSymbol.DecodeConstant(constant, this.MetadataReader); + } + + private SymbolDocumentation BuildDocumentation() => + XmlDocumentationExtractor.Extract(this); + + private string BuildRawDocumentation() => + MetadataSymbol.GetDocumentation(this); +} diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs index c69d01f3ad..ba8ff96f06 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs @@ -158,9 +158,9 @@ private ImmutableArray BuildMembers() // Skip non-public if (!fieldDef.Attributes.HasFlag(FieldAttributes.Public)) continue; // Add it - var fieldSym = new MetadataFieldSymbol( - containingSymbol: this, - fieldDefinition: fieldDef); + var fieldSym = fieldDef.Attributes.HasFlag(FieldAttributes.Static) + ? new MetadataStaticFieldSymbol(containingSymbol: this, fieldDefinition: fieldDef) as Symbol + : new MetadataFieldSymbol(containingSymbol: this, fieldDefinition: fieldDef); result.Add(fieldSym); } From 3ee79e61011ebde9b90764df9a88531c16a6e83a Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Tue, 10 Oct 2023 16:03:04 +0200 Subject: [PATCH 28/55] Killed static field logic --- .../Binding/Binder_BoundExpression.cs | 2 +- .../Internal/Binding/Binder_BoundLvalue.cs | 2 +- .../Binding/Binder_UntypedExpression.cs | 2 -- .../Internal/Binding/Binder_UntypedLvalue.cs | 2 -- .../Internal/BoundTree/BoundNodes.xml | 4 ++-- .../OptimizingIr/FunctionBodyCodegen.cs | 19 ++--------------- .../Symbols/Metadata/MetadataFieldSymbol.cs | 21 ------------------- .../Internal/UntypedTree/UntypedNodes.xml | 4 ++-- 8 files changed, 8 insertions(+), 48 deletions(-) diff --git a/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs b/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs index 615979a3bb..9a4b5de893 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs @@ -109,7 +109,7 @@ private BoundExpression TypeGlobalExpression(UntypedGlobalExpression global, Con private BoundExpression TypeFieldExpression(UntypedFieldExpression field, ConstraintSolver constraints, DiagnosticBag diagnostics) { - var receiver = field.Reciever is null ? null : this.TypeExpression(field.Reciever, constraints, diagnostics); + var receiver = this.TypeExpression(field.Reciever, constraints, diagnostics); return new BoundFieldExpression(field.Syntax, receiver, field.Field); } diff --git a/src/Draco.Compiler/Internal/Binding/Binder_BoundLvalue.cs b/src/Draco.Compiler/Internal/Binding/Binder_BoundLvalue.cs index 294c5775a6..cac23fab59 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_BoundLvalue.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_BoundLvalue.cs @@ -36,7 +36,7 @@ private BoundLvalue TypeGlobalLvalue(UntypedGlobalLvalue global, ConstraintSolve private BoundLvalue TypeFieldLvalue(UntypedFieldLvalue field, ConstraintSolver constraints, DiagnosticBag diagnostics) { - var receiver = field.Reciever is null ? null : this.TypeExpression(field.Reciever, constraints, diagnostics); + var receiver = this.TypeExpression(field.Reciever, constraints, diagnostics); return new BoundFieldLvalue(field.Syntax, receiver, field.Field); } diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs index c431651699..236d3028e6 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs @@ -757,8 +757,6 @@ private UntypedExpression SymbolToExpression(SyntaxNode syntax, Symbol symbol, C return new UntypedLocalExpression(syntax, local, constraints.GetLocalType(local)); case GlobalSymbol global: return new UntypedGlobalExpression(syntax, global); - case FieldSymbol field: - return new UntypedFieldExpression(syntax, null, field); case PropertySymbol prop: var getter = GetGetterSymbol(syntax, prop, diagnostics); return new UntypedPropertyGetExpression(syntax, null, getter); diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs index 827b256508..49966e6289 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs @@ -149,8 +149,6 @@ private UntypedLvalue SymbolToLvalue(SyntaxNode syntax, Symbol symbol, Constrain { case GlobalSymbol global: return new UntypedGlobalLvalue(syntax, global); - case FieldSymbol field: - return new UntypedFieldLvalue(syntax, null, field); case PropertySymbol prop: var setter = GetSetterSymbol(syntax, prop, diagnostics); return new UntypedPropertySetLvalue(syntax, null, setter); diff --git a/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml b/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml index aa95b43cc3..825831fd25 100644 --- a/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml +++ b/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml @@ -187,7 +187,7 @@ - + @@ -280,7 +280,7 @@ - + diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 712445d2fe..7467cff05e 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -549,24 +549,9 @@ private FunctionInstanceSymbol TranslateFunctionInstanceSymbol(FunctionInstanceS public override IOperand VisitFieldExpression(BoundFieldExpression node) { - // Check, if it's a literal we need to inline - var metadataField = ExtractMetadataField(node.Field); - if (metadataField is not null && metadataField.IsLiteral) - { - var defaultValue = metadataField.DefaultValue; - if (!BinderFacts.TryGetLiteralType(defaultValue, this.compilation.IntrinsicSymbols, out var literalType)) - { - throw new System.InvalidOperationException(); - } - return new Constant(defaultValue, literalType); - } - - // Regular static or nonstatic field - var receiver = node.Receiver is null ? null : this.Compile(node.Receiver); + var receiver = this.Compile(node.Receiver); var result = this.DefineRegister(node.TypeRequired); - this.Write(receiver is null - ? Load(result, node.Field) - : LoadField(result, receiver, node.Field)); + this.Write(LoadField(result, receiver, node.Field)); return result; } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs index f7d53ebeb2..51c5d54c5d 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs @@ -55,18 +55,6 @@ public override Api.Semantics.Visibility Visibility /// public MetadataReader MetadataReader => this.Assembly.MetadataReader; - /// - /// True, if this is a literal that cannot be referenced as a field, but needs to be inlined as a value. - /// This is the case for enum members. - /// - public bool IsLiteral => this.fieldDefinition.Attributes.HasFlag(FieldAttributes.Literal); - - /// - /// The default value of this field. - /// - public object? DefaultValue => InterlockedUtils.InitializeMaybeNull(ref this.defaultValue, this.BuildDefaultValue); - private object? defaultValue; - private readonly FieldDefinition fieldDefinition; public MetadataFieldSymbol(Symbol containingSymbol, FieldDefinition fieldDefinition) @@ -83,15 +71,6 @@ public MetadataFieldSymbol(Symbol containingSymbol, FieldDefinition fieldDefinit private TypeSymbol BuildType() => this.fieldDefinition.DecodeSignature(this.Assembly.Compilation.TypeProvider, this); - private object? BuildDefaultValue() - { - var constantHandle = this.fieldDefinition.GetDefaultValue(); - if (constantHandle.IsNil) return null; - - var constant = this.MetadataReader.GetConstant(constantHandle); - return MetadataSymbol.DecodeConstant(constant, this.MetadataReader); - } - private SymbolDocumentation BuildDocumentation() => XmlDocumentationExtractor.Extract(this); diff --git a/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml b/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml index 440ddc1569..02f8217858 100644 --- a/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml +++ b/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml @@ -151,7 +151,7 @@ - + @@ -241,7 +241,7 @@ - + From f4ce76f217037fc37006f39e913df5c198db2257 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Tue, 10 Oct 2023 18:43:03 +0200 Subject: [PATCH 29/55] Added AddressOf --- .../Internal/Codegen/CilCodegen.cs | 17 ---------- .../OptimizingIr/FunctionBodyCodegen.cs | 14 ++++---- .../OptimizingIr/InstructionFactory.cs | 1 + .../Internal/OptimizingIr/Model/Address.cs | 14 -------- .../Model/AddressOfInstruction.cs | 32 +++++++++++++++++++ .../Internal/Symbols/ReferenceTypeSymbol.cs | 28 ++++++++++++++++ 6 files changed, 68 insertions(+), 38 deletions(-) delete mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/Address.cs create mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs create mode 100644 src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index ea44d553ab..8453fc315a 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -418,23 +418,6 @@ private void EncodePush(IOperand operand) case Register r: this.LoadRegister(r); break; - case Address a: - switch (a.Operand) - { - // TODO - /* - case Local local: - { - var index = this.GetLocalIndex(local); - if (index is null) break; - this.InstructionEncoder.LoadLocalAddress(index.Value); - break; - } - */ - default: - throw new NotImplementedException(); - } - break; case Constant c: switch (c.Value) { diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 7467cff05e..beaf90e55a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -233,22 +233,22 @@ private IOperand CompileToAddress(BoundExpression expression) { case BoundLocalExpression local: { - // TODO - // return new Address(localOperand); - // TODO - throw new System.NotImplementedException(); + var target = this.DefineRegister(new ReferenceTypeSymbol(local.TypeRequired)); + this.Write(AddressOf(target, local.Local)); + return target; } default: { // We allocate a local so we can take its address var local = new SynthetizedLocalSymbol(expression.TypeRequired, false); + this.procedure.DefineLocal(local); // Store the value in it var value = this.Compile(expression); this.Write(Store(local, value)); // Take its address - // return new Address(localOperand); - // TODO - throw new System.NotImplementedException(); + var target = this.DefineRegister(new ReferenceTypeSymbol(expression.TypeRequired)); + this.Write(AddressOf(target, local)); + return target; } } } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs b/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs index 907e9429cd..ffcf33c6e0 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/InstructionFactory.cs @@ -23,6 +23,7 @@ public static LoadElementInstruction LoadElement(Register target, IOperand array new(target, array, indices); public static LoadFieldInstruction LoadField(Register target, IOperand receiver, FieldSymbol field) => new(target, receiver, field); + public static AddressOfInstruction AddressOf(Register target, Symbol source) => new(target, source); public static RetInstruction Ret(IOperand value) => new(value); public static JumpInstruction Jump(BasicBlock target) => new(target); public static BranchInstruction Branch(IOperand condition, BasicBlock then, BasicBlock @else) => diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Address.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Address.cs deleted file mode 100644 index 2330c5a18f..0000000000 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Address.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Draco.Compiler.Internal.Symbols; - -namespace Draco.Compiler.Internal.OptimizingIr.Model; - -/// -/// References the address of a local or global. -/// -/// The symbol to reference the address of. -internal readonly record struct Address(IOperand Operand) : IOperand -{ - public TypeSymbol? Type => null; - - public string ToOperandString() => $"(ref {this.Operand.ToOperandString()})"; -} diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs new file mode 100644 index 0000000000..eb6d85123a --- /dev/null +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Draco.Compiler.Internal.Symbols; + +namespace Draco.Compiler.Internal.OptimizingIr.Model; + +/// +/// Loads the address of some local/global/argument. +/// +internal sealed class AddressOfInstruction : InstructionBase, IValueInstruction +{ + public Register Target { get; set; } + + /// + /// The operand to load from. + /// + public Symbol Source { get; set; } + + public AddressOfInstruction(Register target, Symbol source) + { + this.Target = target; + this.Source = source; + } + + public override string ToString() => + $"{this.Target.ToOperandString()} := addressof {this.Source.FullName}"; + + public override AddressOfInstruction Clone() => new(this.Target, this.Source); +} diff --git a/src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs new file mode 100644 index 0000000000..fb2b3c98f5 --- /dev/null +++ b/src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Draco.Compiler.Internal.Symbols; + +/// +/// Represents a reference type. +/// +internal sealed class ReferenceTypeSymbol : TypeSymbol +{ + /// + /// The element type that the reference references to. + /// + public TypeSymbol ElementType { get; } + + public override bool IsValueType => true; + public override Symbol? ContainingSymbol => null; + + public ReferenceTypeSymbol(TypeSymbol elementType) + { + this.ElementType = elementType; + } + + public override string ToString() => $"ref {this.ElementType}"; +} From 938c35a56c657096389c961297fb6320c4ef4326 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Tue, 10 Oct 2023 18:48:55 +0200 Subject: [PATCH 30/55] Addresses work --- .../Internal/Codegen/CilCodegen.cs | 24 +++++++++++++++++++ .../Internal/Codegen/MetadataCodegen.cs | 6 +++++ 2 files changed, 30 insertions(+) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 8453fc315a..35eb71125b 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -318,6 +318,30 @@ private void EncodeInstruction(IInstruction instruction) this.InstructionEncoder.Token(this.GetHandle(storeField.Member)); break; } + case AddressOfInstruction addressOf: + { + switch (addressOf.Source) + { + case ParameterSymbol local: + { + var paramIndex = this.GetParameterIndex(local); + this.InstructionEncoder.LoadArgumentAddress(paramIndex); + this.StoreLocal(addressOf.Target); + break; + } + case LocalSymbol local: + { + var localIndex = this.GetLocalIndex(local); + Debug.Assert(localIndex is not null); + this.InstructionEncoder.LoadLocalAddress(localIndex.Value); + this.StoreLocal(addressOf.Target); + break; + } + default: + throw new InvalidOperationException(); + } + break; + } case CallInstruction call: { // Arguments diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index d0a02bbd5a..c4326c094d 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -670,6 +670,12 @@ public void EncodeSignatureType(SignatureTypeEncoder encoder, TypeSymbol type) } } + if (type is ReferenceTypeSymbol referenceType) + { + this.EncodeSignatureType(encoder.Pointer(), referenceType.ElementType); + return; + } + // TODO throw new NotImplementedException(); } From 0204cc8d0bec3f21ca60c5f75050cc1919fc0637 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Wed, 11 Oct 2023 21:40:20 +0200 Subject: [PATCH 31/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 35eb71125b..349ee081a9 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -77,8 +77,8 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) .ToImmutableDictionary(pair => pair.Local, pair => new AllocatedLocal(pair.Local, pair.Index)); this.allocatedRegisters = procedure.Registers .Where(reg => !SymbolEqualityComparer.Default.Equals(reg.Type, IntrinsicSymbols.Unit)) - .Select((local, index) => (Local: local, Index: index)) - .ToImmutableDictionary(pair => pair.Local, pair => this.allocatedLocals.Count + pair.Index); + .Select((reg, index) => (Register: reg, Index: index)) + .ToImmutableDictionary(pair => pair.Register, pair => this.allocatedLocals.Count + pair.Index); } private UserStringHandle GetStringLiteralHandle(string text) => this.metadataCodegen.GetStringLiteralHandle(text); From a084815ac2c0f20382d91d45beb44f4c9c06845c Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 09:41:13 +0200 Subject: [PATCH 32/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 349ee081a9..12002b2d46 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -210,14 +210,6 @@ private void EncodeInstruction(IInstruction instruction) this.EncodeToken(global); break; } - // TODO: REALLY MERGE static fields with globals! - case FieldSymbol field: - { - Debug.Assert(field.IsStatic); - this.InstructionEncoder.OpCode(ILOpCode.Ldsfld); - this.EncodeToken(field); - break; - } default: throw new InvalidOperationException(); } @@ -273,13 +265,6 @@ private void EncodeInstruction(IInstruction instruction) this.InstructionEncoder.OpCode(ILOpCode.Stsfld); this.EncodeToken(global); break; - // TODO: REALLY MERGE static fields with globals! - case FieldSymbol field: - Debug.Assert(field.IsStatic); - this.EncodePush(store.Source); - this.InstructionEncoder.OpCode(ILOpCode.Stsfld); - this.EncodeToken(field); - break; default: throw new InvalidOperationException(); } From b8f1521e93fda5cb2ad309bed3e72a09ff318546 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 09:47:37 +0200 Subject: [PATCH 33/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 12002b2d46..e5c6dec53d 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -307,9 +307,9 @@ private void EncodeInstruction(IInstruction instruction) { switch (addressOf.Source) { - case ParameterSymbol local: + case ParameterSymbol param: { - var paramIndex = this.GetParameterIndex(local); + var paramIndex = this.GetParameterIndex(param); this.InstructionEncoder.LoadArgumentAddress(paramIndex); this.StoreLocal(addressOf.Target); break; @@ -317,11 +317,19 @@ private void EncodeInstruction(IInstruction instruction) case LocalSymbol local: { var localIndex = this.GetLocalIndex(local); + // NOTE: What if we ask the address of a unit? Debug.Assert(localIndex is not null); this.InstructionEncoder.LoadLocalAddress(localIndex.Value); this.StoreLocal(addressOf.Target); break; } + case GlobalSymbol global: + { + this.InstructionEncoder.OpCode(ILOpCode.Ldsflda); + this.EncodeToken(global); + this.StoreLocal(addressOf.Target); + break; + } default: throw new InvalidOperationException(); } From 6d27273a2d99901c3908364f3196c7e902dfe884 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 09:56:38 +0200 Subject: [PATCH 34/55] Update MetadataStaticFieldSymbol.cs --- .../Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs index 61e670046d..eb68a30d31 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs @@ -7,8 +7,6 @@ namespace Draco.Compiler.Internal.Symbols.Metadata; -// TODO: Copypasta from metadata field - /// /// Static fields read from metadata. /// From b72b34c605a71d2f4b9599257199974f6c30bde0 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 14:17:54 +0200 Subject: [PATCH 35/55] Added tree instruction --- .../Model/AddressOfInstruction.cs | 4 +- .../Model/ArithmeticInstruction.cs | 2 + .../Model/ArrayLengthInstruction.cs | 4 +- .../OptimizingIr/Model/BoxInstruction.cs | 4 +- .../OptimizingIr/Model/CallInstruction.cs | 4 +- .../Internal/OptimizingIr/Model/Constant.cs | 2 +- .../Internal/OptimizingIr/Model/IOperand.cs | 4 +- .../OptimizingIr/Model/IValueInstruction.cs | 7 +++- .../Model/LoadElementInstruction.cs | 4 +- .../Model/LoadFieldInstruction.cs | 4 +- .../OptimizingIr/Model/LoadInstruction.cs | 4 +- .../Model/MemberCallInstruction.cs | 4 +- .../OptimizingIr/Model/NewArrayInstruction.cs | 4 +- .../Model/NewObjectInstruction.cs | 4 +- .../OptimizingIr/Model/TreeInstruction.cs | 42 +++++++++++++++++++ 15 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs index eb6d85123a..4d5b2360c2 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs @@ -12,6 +12,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class AddressOfInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "addressof"; + public Register Target { get; set; } /// @@ -26,7 +28,7 @@ public AddressOfInstruction(Register target, Symbol source) } public override string ToString() => - $"{this.Target.ToOperandString()} := addressof {this.Source.FullName}"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.Source.FullName}"; public override AddressOfInstruction Clone() => new(this.Target, this.Source); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs index a20e572138..7bef5ab406 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class ArithmeticInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => this.OpToString(); + public Register Target { get; set; } /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs index 83a1506ebd..5bbe065aa9 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs @@ -7,6 +7,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class ArrayLengthInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "length"; + public Register Target { get; set; } /// @@ -23,7 +25,7 @@ public ArrayLengthInstruction(Register target, IOperand array) } public override string ToString() => - $"{this.Target.ToOperandString()} := length {this.Array.ToOperandString()}"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.Array.ToOperandString()}"; public override ArrayLengthInstruction Clone() => new(this.Target, this.Array); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs index e923f554ec..ea001fbe89 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class BoxInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "box"; + public Register Target { get; set; } /// @@ -30,7 +32,7 @@ public BoxInstruction(Register target, TypeSymbol boxedType, IOperand value) } public override string ToString() => - $"{this.Target.ToOperandString()} := box {this.Value.ToOperandString()} as {this.BoxedType}"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.Value.ToOperandString()} as {this.BoxedType}"; public override BoxInstruction Clone() => new(this.Target, this.BoxedType, this.Value); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs index 6b0a2e65c2..f4c8c53135 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs @@ -9,6 +9,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class CallInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "call"; + public Register Target { get; set; } /// @@ -31,7 +33,7 @@ public CallInstruction(Register target, FunctionSymbol procedure, IEnumerable - $"{this.Target.ToOperandString()} := call [{this.Procedure.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} [{this.Procedure.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; public override CallInstruction Clone() => new(this.Target, this.Procedure, this.Arguments); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Constant.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Constant.cs index cda0859b8f..dd83742790 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Constant.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/Constant.cs @@ -8,7 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// The constant value. /// The type of the constant. -internal readonly record struct Constant(object? Value, TypeSymbol? Type) : IOperand +internal readonly record struct Constant(object? Value, TypeSymbol Type) : IOperand { public override string ToString() => this.ToOperandString(); public string ToOperandString() => this.Value switch diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IOperand.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IOperand.cs index b48e0d718c..a93f349874 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IOperand.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IOperand.cs @@ -8,9 +8,9 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; internal interface IOperand { /// - /// The type of this operand, in case it's a value. + /// The type of this operand. /// - public TypeSymbol? Type { get; } + public TypeSymbol Type { get; } /// /// Returns a string representation of the operand. diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs index f3d76e4e8a..4c07207858 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs @@ -9,8 +9,13 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// /// An instruction that produces a result in a register. /// -internal interface IValueInstruction +internal interface IValueInstruction : IInstruction { + /// + /// The keyword notating the instruction. + /// + public string InstructionKeyword { get; } + /// /// The register to store the result at. /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs index 62ab16c4e8..85c44d4078 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class LoadElementInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "loadelement"; + public Register Target { get; set; } /// @@ -30,7 +32,7 @@ public LoadElementInstruction(Register target, IOperand array, IEnumerable - $"{this.Target.ToOperandString()} := load {this.Array.ToOperandString()}[{string.Join(", ", this.Indices.Select(d => d.ToOperandString()))}]"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.Array.ToOperandString()}[{string.Join(", ", this.Indices.Select(d => d.ToOperandString()))}]"; public override LoadElementInstruction Clone() => new(this.Target, this.Array, this.Indices); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs index 1fa504f35d..5586a387db 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class LoadFieldInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "loadfield"; + public Register Target { get; set; } /// @@ -30,7 +32,7 @@ public LoadFieldInstruction(Register target, IOperand receiver, FieldSymbol memb } public override string ToString() => - $"{this.Target.ToOperandString()} := load {this.Receiver.ToOperandString()}.{this.Member.Name}"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.Receiver.ToOperandString()}.{this.Member.Name}"; public override LoadFieldInstruction Clone() => new(this.Target, this.Receiver, this.Member); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs index 26063eb698..b58c2b15a4 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class LoadInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "load"; + public Register Target { get; set; } /// @@ -22,7 +24,7 @@ public LoadInstruction(Register target, Symbol source) } public override string ToString() => - $"{this.Target.ToOperandString()} := load {this.Source.FullName}"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.Source.FullName}"; public override LoadInstruction Clone() => new(this.Target, this.Source); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs index e5d49feb37..1e50bbf302 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs @@ -9,6 +9,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class MemberCallInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "membercall"; + public Register Target { get; set; } /// @@ -37,7 +39,7 @@ public MemberCallInstruction(Register target, FunctionSymbol procedure, IOperand } public override string ToString() => - $"{this.Target.ToOperandString()} := call {this.Receiver.ToOperandString()}.[{this.Procedure.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.Receiver.ToOperandString()}.[{this.Procedure.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; public override MemberCallInstruction Clone() => new(this.Target, this.Procedure, this.Receiver, this.Arguments); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs index 4e47ab6b11..dc11a68564 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs @@ -9,6 +9,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class NewArrayInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "newarray"; + public Register Target { get; set; } /// @@ -31,7 +33,7 @@ public NewArrayInstruction(Register target, TypeSymbol elementType, IEnumerable< } public override string ToString() => - $"{this.Target.ToOperandString()} := new {this.ElementType}[{string.Join(", ", this.Dimensions.Select(d => d.ToOperandString()))}]"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} {this.ElementType}[{string.Join(", ", this.Dimensions.Select(d => d.ToOperandString()))}]"; public override NewArrayInstruction Clone() => new(this.Target, this.ElementType, this.Dimensions); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs index 595222c096..df3200df8e 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs @@ -9,6 +9,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class NewObjectInstruction : InstructionBase, IValueInstruction { + public string InstructionKeyword => "newobject"; + public Register Target { get; set; } /// @@ -31,7 +33,7 @@ public NewObjectInstruction(Register target, FunctionSymbol constructor, IEnumer } public override string ToString() => - $"{this.Target.ToOperandString()} := new [{this.Constructor.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; + $"{this.Target.ToOperandString()} := {this.InstructionKeyword} [{this.Constructor.FullName}]({string.Join(", ", this.Arguments.Select(a => a.ToOperandString()))})"; public override NewObjectInstruction Clone() => new(this.Target, this.Constructor, this.Arguments); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs new file mode 100644 index 0000000000..0e629e6f09 --- /dev/null +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Draco.Compiler.Internal.Symbols; + +namespace Draco.Compiler.Internal.OptimizingIr.Model; + +/// +/// Represents a tree-ified instruction, that's only part of the stackification process. +/// Not an actual instruction, it's a wrapper to signal structural changes. +/// +internal sealed class TreeInstruction : InstructionBase, IOperand, IValueInstruction +{ + public string InstructionKeyword => this.Underlying.InstructionKeyword; + + public Register Target => this.Underlying.Target; + + /// + /// The original, non-tree instruction. + /// + public IValueInstruction Underlying { get; } + + public override bool IsBranch => this.Underlying.IsBranch; + public override IEnumerable JumpTargets => this.Underlying.JumpTargets.Cast(); + public override IEnumerable Operands { get; } + + public TypeSymbol Type => this.Target.Type; + + public TreeInstruction(IValueInstruction underlying, ImmutableArray operands) + { + this.Underlying = underlying; + this.Operands = operands; + } + + public override string ToString() => $"{this.Target} := {this.ToOperandString()}"; + public string ToOperandString() => $"{this.InstructionKeyword}({string.Join(", ", this.Operands)})"; + public override IInstruction Clone() => + new TreeInstruction((IValueInstruction)this.Underlying.Clone(), this.Operands.ToImmutableArray()); +} From 13db761458cedc2649796e02c15f264ff3a3bb4c Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 14:18:12 +0200 Subject: [PATCH 36/55] Update TreeInstruction.cs --- .../Internal/OptimizingIr/Model/TreeInstruction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs index 0e629e6f09..c5e9e5278a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs @@ -36,7 +36,7 @@ public TreeInstruction(IValueInstruction underlying, ImmutableArray op } public override string ToString() => $"{this.Target} := {this.ToOperandString()}"; - public string ToOperandString() => $"{this.InstructionKeyword}({string.Join(", ", this.Operands)})"; + public string ToOperandString() => $"{this.InstructionKeyword}({string.Join(", ", this.Operands.Select(op => op.ToOperandString()))})"; public override IInstruction Clone() => new TreeInstruction((IValueInstruction)this.Underlying.Clone(), this.Operands.ToImmutableArray()); } From 6fadb0a572ceaf2c9c5ed36166155f9df4db9da5 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 14:21:01 +0200 Subject: [PATCH 37/55] Update TreeInstruction.cs --- .../Internal/OptimizingIr/Model/TreeInstruction.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs index c5e9e5278a..2bec0cc260 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs @@ -31,6 +31,8 @@ internal sealed class TreeInstruction : InstructionBase, IOperand, IValueInstruc public TreeInstruction(IValueInstruction underlying, ImmutableArray operands) { + if (underlying is TreeInstruction) throw new ArgumentOutOfRangeException(nameof(underlying)); + this.Underlying = underlying; this.Operands = operands; } From a9cabb2d0681a1e6791d2b466e881afaee8c1f19 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 14:40:27 +0200 Subject: [PATCH 38/55] Fixes in tree instr --- .../Model/AddressOfInstruction.cs | 2 +- .../Model/ArithmeticInstruction.cs | 2 +- .../Model/ArrayLengthInstruction.cs | 2 +- .../OptimizingIr/Model/BoxInstruction.cs | 2 +- .../OptimizingIr/Model/BranchInstruction.cs | 1 + .../OptimizingIr/Model/CallInstruction.cs | 2 +- .../Internal/OptimizingIr/Model/EndScope.cs | 4 +- .../OptimizingIr/Model/IInstruction.cs | 5 +++ .../OptimizingIr/Model/IValueInstruction.cs | 5 --- .../OptimizingIr/Model/InstructionBase.cs | 2 + .../OptimizingIr/Model/JumpInstruction.cs | 3 +- .../Model/LoadElementInstruction.cs | 2 +- .../Model/LoadFieldInstruction.cs | 2 +- .../OptimizingIr/Model/LoadInstruction.cs | 2 +- .../Model/MemberCallInstruction.cs | 2 +- .../OptimizingIr/Model/NewArrayInstruction.cs | 2 +- .../Model/NewObjectInstruction.cs | 2 +- .../OptimizingIr/Model/NopInstruction.cs | 4 +- .../OptimizingIr/Model/RetInstruction.cs | 4 +- .../OptimizingIr/Model/SequencePoint.cs | 4 +- .../Internal/OptimizingIr/Model/StartScope.cs | 4 +- .../Model/StoreElementInstruction.cs | 4 +- .../Model/StoreFieldInstruction.cs | 4 +- .../OptimizingIr/Model/StoreInstruction.cs | 4 +- .../OptimizingIr/Model/TreeInstruction.cs | 10 ++--- .../Internal/OptimizingIr/Stackifier.cs | 42 +++++++++---------- 26 files changed, 70 insertions(+), 52 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs index 4d5b2360c2..6b9c131f28 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs @@ -12,7 +12,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class AddressOfInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "addressof"; + public override string InstructionKeyword => "addressof"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs index 7bef5ab406..ae4ee4384f 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArithmeticInstruction.cs @@ -8,7 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class ArithmeticInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => this.OpToString(); + public override string InstructionKeyword => this.OpToString(); public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs index 5bbe065aa9..67246c7c9d 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/ArrayLengthInstruction.cs @@ -7,7 +7,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class ArrayLengthInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "length"; + public override string InstructionKeyword => "length"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs index ea001fbe89..2bd2567c0a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs @@ -8,7 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class BoxInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "box"; + public override string InstructionKeyword => "box"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs index 329a53caef..2389ce853e 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs @@ -8,6 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class BranchInstruction : InstructionBase { + public override string InstructionKeyword => "jump_if"; public override bool IsBranch => true; public override IEnumerable JumpTargets => new[] { this.Then, this.Else }; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs index f4c8c53135..e57b7a25d4 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs @@ -9,7 +9,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class CallInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "call"; + public override string InstructionKeyword => "call"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs index 4d73d2fa93..a5743c2c6b 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs @@ -8,9 +8,11 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class EndScope : InstructionBase { + public override string InstructionKeyword => "@scope end"; + public override bool IsValidInUnreachableContext => true; public override EndScope Clone() => new(); - public override string ToString() => "@scope end"; + public override string ToString() => this.InstructionKeyword; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs index 8e7d25bc33..73ead9eec7 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs @@ -7,6 +7,11 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal interface IInstruction { + /// + /// The keyword notating the instruction. + /// + public string InstructionKeyword { get; } + /// /// The basic block this instruction is a part of. /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs index 4c07207858..7d4baff395 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs @@ -11,11 +11,6 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal interface IValueInstruction : IInstruction { - /// - /// The keyword notating the instruction. - /// - public string InstructionKeyword { get; } - /// /// The register to store the result at. /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs index 4b3c83a328..ac7cc64d94 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal abstract class InstructionBase : IInstruction { + public abstract string InstructionKeyword { get; } + public BasicBlock BasicBlock { get; set; } = null!; IBasicBlock IInstruction.BasicBlock => this.BasicBlock; public InstructionBase? Prev { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs index c8285c385c..673bcadcfe 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs @@ -8,6 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class JumpInstruction : InstructionBase { + public override string InstructionKeyword => "jump"; public override bool IsBranch => true; public override IEnumerable JumpTargets => new[] { this.Target }; @@ -21,7 +22,7 @@ public JumpInstruction(BasicBlock target) this.Target = target; } - public override string ToString() => $"jump lbl{this.Target.Index}"; + public override string ToString() => $"{this.InstructionKeyword} lbl{this.Target.Index}"; public override JumpInstruction Clone() => new(this.Target); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs index 85c44d4078..067f6079ef 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadElementInstruction.cs @@ -8,7 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class LoadElementInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "loadelement"; + public override string InstructionKeyword => "loadelement"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs index 5586a387db..1c30a2613b 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs @@ -8,7 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class LoadFieldInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "loadfield"; + public override string InstructionKeyword => "loadfield"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs index b58c2b15a4..99ed4d0f15 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs @@ -8,7 +8,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class LoadInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "load"; + public override string InstructionKeyword => "load"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs index 1e50bbf302..69c9fdfaf7 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs @@ -9,7 +9,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class MemberCallInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "membercall"; + public override string InstructionKeyword => "membercall"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs index dc11a68564..f9692f3a7e 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs @@ -9,7 +9,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class NewArrayInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "newarray"; + public override string InstructionKeyword => "newarray"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs index df3200df8e..482007dbb9 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs @@ -9,7 +9,7 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class NewObjectInstruction : InstructionBase, IValueInstruction { - public string InstructionKeyword => "newobject"; + public override string InstructionKeyword => "newobject"; public Register Target { get; set; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs index 17a53ac1a7..462f172244 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs @@ -8,7 +8,9 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class NopInstruction : InstructionBase { - public override string ToString() => "nop"; + public override string InstructionKeyword => "nop"; + + public override string ToString() => this.InstructionKeyword; public override NopInstruction Clone() => new(); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs index c364a9be52..bf2a209fc4 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/RetInstruction.cs @@ -7,6 +7,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class RetInstruction : InstructionBase { + public override string InstructionKeyword => "ret"; + public override bool IsBranch => true; /// @@ -21,7 +23,7 @@ public RetInstruction(IOperand value) this.Value = value; } - public override string ToString() => $"ret {this.Value.ToOperandString()}"; + public override string ToString() => $"{this.InstructionKeyword} {this.Value.ToOperandString()}"; public override RetInstruction Clone() => new(this.Value); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs index f912d5d8c3..1fcb691134 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs @@ -10,6 +10,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class SequencePoint : InstructionBase { + public override string InstructionKeyword => "@sequence point"; + /// /// The range this sequence point corresponds to, if any. /// @@ -25,7 +27,7 @@ public SequencePoint(SyntaxRange? range) public override string ToString() { var result = new StringBuilder(); - result.Append("@sequence point"); + result.Append(this.InstructionKeyword); if (this.Range is not null) { var start = this.Range.Value.Start; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StartScope.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StartScope.cs index ea1225ada6..89fdc4a403 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StartScope.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StartScope.cs @@ -11,6 +11,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class StartScope : InstructionBase { + public override string InstructionKeyword => "@scope start"; + /// /// The locals introduced in this scope. /// @@ -28,7 +30,7 @@ public StartScope(IEnumerable locals) public override string ToString() { var result = new StringBuilder(); - result.Append("@scope start ["); + result.Append($"{this.InstructionKeyword} ["); result.AppendJoin(", ", this.Locals.Select(x => x.Name)); result.Append(']'); return result.ToString(); diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs index abbfb97615..abbe1e22a2 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreElementInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class StoreElementInstruction : InstructionBase { + public override string InstructionKeyword => "storeelement"; + /// /// The array to store to. /// @@ -33,7 +35,7 @@ public StoreElementInstruction(IOperand targetArray, IEnumerable indic } public override string ToString() => - $"store {this.TargetArray.ToOperandString()}[{string.Join(", ", this.Indices.Select(i => i.ToOperandString()))}] := {this.Source.ToOperandString()}"; + $"{this.InstructionKeyword} {this.TargetArray.ToOperandString()}[{string.Join(", ", this.Indices.Select(i => i.ToOperandString()))}] := {this.Source.ToOperandString()}"; public override StoreElementInstruction Clone() => new(this.TargetArray, this.Indices, this.Source); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs index d3eadf439b..f286a2f798 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class StoreFieldInstruction : InstructionBase { + public override string InstructionKeyword => "storefield"; + /// /// The accessed object. /// @@ -33,7 +35,7 @@ public StoreFieldInstruction(IOperand receiver, FieldSymbol member, IOperand sou } public override string ToString() => - $"store {this.Receiver.ToOperandString()}.{this.Member.Name} := {this.Source.ToOperandString()}"; + $"{this.InstructionKeyword} {this.Receiver.ToOperandString()}.{this.Member.Name} := {this.Source.ToOperandString()}"; public override StoreFieldInstruction Clone() => new(this.Receiver, this.Member, this.Source); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs index 1a6008eba2..597e5c29d0 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs @@ -8,6 +8,8 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class StoreInstruction : InstructionBase { + public override string InstructionKeyword => "store"; + /// /// The symbol to store to. /// @@ -26,7 +28,7 @@ public StoreInstruction(Symbol target, IOperand source) this.Source = source; } - public override string ToString() => $"store {this.Target.FullName} := {this.Source.ToOperandString()}"; + public override string ToString() => $"{this.InstructionKeyword} {this.Target.FullName} := {this.Source.ToOperandString()}"; public override StoreInstruction Clone() => new(this.Target, this.Source); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs index 2bec0cc260..619a7ee69c 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs @@ -14,14 +14,14 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; /// internal sealed class TreeInstruction : InstructionBase, IOperand, IValueInstruction { - public string InstructionKeyword => this.Underlying.InstructionKeyword; + public override string InstructionKeyword => this.Underlying.InstructionKeyword; - public Register Target => this.Underlying.Target; + public Register Target => (this.Underlying as IValueInstruction)!.Target; /// /// The original, non-tree instruction. /// - public IValueInstruction Underlying { get; } + public IInstruction Underlying { get; } public override bool IsBranch => this.Underlying.IsBranch; public override IEnumerable JumpTargets => this.Underlying.JumpTargets.Cast(); @@ -29,7 +29,7 @@ internal sealed class TreeInstruction : InstructionBase, IOperand, IValueInstruc public TypeSymbol Type => this.Target.Type; - public TreeInstruction(IValueInstruction underlying, ImmutableArray operands) + public TreeInstruction(IInstruction underlying, ImmutableArray operands) { if (underlying is TreeInstruction) throw new ArgumentOutOfRangeException(nameof(underlying)); @@ -40,5 +40,5 @@ public TreeInstruction(IValueInstruction underlying, ImmutableArray op public override string ToString() => $"{this.Target} := {this.ToOperandString()}"; public string ToOperandString() => $"{this.InstructionKeyword}({string.Join(", ", this.Operands.Select(op => op.ToOperandString()))})"; public override IInstruction Clone() => - new TreeInstruction((IValueInstruction)this.Underlying.Clone(), this.Operands.ToImmutableArray()); + new TreeInstruction(this.Underlying.Clone(), this.Operands.ToImmutableArray()); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs index 75fcf59e15..8d54e28732 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -13,21 +13,6 @@ namespace Draco.Compiler.Internal.OptimizingIr; /// internal sealed class Stackifier { - /// - /// Stackifies the given procedure without rearranging instructions. - /// - /// The procedure to stackify. - /// The registers that got stackified. - public static ImmutableHashSet Stackify(IProcedure procedure) - { - var stackifier = new Stackifier(procedure); - foreach (var bb in procedure.BasicBlocks.Values) stackifier.Stackify(bb); - // Subtract to get stackified regs - return stackifier.registerUses.Keys - .Except(stackifier.savedRegisters) - .ToImmutableHashSet(); - } - private static ImmutableDictionary CountRegisterUses(IEnumerable instructions) { var registerUses = ImmutableDictionary.CreateBuilder(); @@ -43,9 +28,8 @@ private static ImmutableDictionary CountRegisterUses(IEnumerable< private readonly IProcedure procedure; private readonly ImmutableDictionary registerUses; - private readonly HashSet savedRegisters = new(); - private Stackifier(IProcedure procedure) + public Stackifier(IProcedure procedure) { this.procedure = procedure; var instructions = procedure.BasicBlocks.Values.SelectMany(bb => bb.Instructions); @@ -53,7 +37,8 @@ private Stackifier(IProcedure procedure) this.registerUses = CountRegisterUses(instructions); } - private void Stackify(IBasicBlock basicBlock) + // TODO: Doc + public ImmutableArray Stackify(IBasicBlock basicBlock) { var instr = basicBlock.LastInstruction; while (instr is not null) @@ -67,15 +52,20 @@ private void Stackify(IBasicBlock basicBlock) } } - private bool RecoverTree(ref IInstruction instrIterator) + private (IOperand Tree, bool Stopped) RecoverTree(ref IInstruction instrIterator) { var instr = instrIterator; + var children = ImmutableArray.CreateBuilder(); var stopped = false; foreach (var op in instr.Operands.Reverse()) { // Not a register, pushed some other way, does not break tree - if (op is not Register reg) continue; + if (op is not Register reg) + { + children.Add(op); + continue; + } // If we have a single-use register as a result immediately before this instruction, // all good, part of the tree @@ -85,16 +75,24 @@ private bool RecoverTree(ref IInstruction instrIterator) && valueInstr.Target == reg) { instrIterator = instrIterator.Prev; - var childStopped = this.RecoverTree(ref instrIterator); + var (childTree, childStopped) = this.RecoverTree(ref instrIterator); + children.Add(childTree); // If child recovery broke the tree, we break too if (childStopped) stopped = true; continue; } // Match failure, need to break the tree + children.Add(op); stopped = true; } - return stopped; + children.Reverse(); + var tree = instr switch + { + IValueInstruction vi => new TreeInstruction(vi, children.ToImmutable()), + _ => throw new InvalidOperationException(), + }; + return (tree, stopped); } } From 5885953f6a9d4e3d01887a2b3365f9b02c393e82 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 14:43:42 +0200 Subject: [PATCH 39/55] Update Stackifier.cs --- .../Internal/OptimizingIr/Stackifier.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs index 8d54e28732..0c92466284 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -40,19 +40,24 @@ public Stackifier(IProcedure procedure) // TODO: Doc public ImmutableArray Stackify(IBasicBlock basicBlock) { + var result = ImmutableArray.CreateBuilder(); + var instr = basicBlock.LastInstruction; while (instr is not null) { - // This instruction has to have its registers saved - if (instr is IValueInstruction valueInstr) this.savedRegisters.Add(valueInstr.Target); // Recover the longest tree backwards - this.RecoverTree(ref instr); + var (tree, _) = this.RecoverTree(ref instr); + // Add result + result.Add(tree); // Step back instr = instr.Prev; } + + result.Reverse(); + return result.ToImmutable(); } - private (IOperand Tree, bool Stopped) RecoverTree(ref IInstruction instrIterator) + private (TreeInstruction Tree, bool Stopped) RecoverTree(ref IInstruction instrIterator) { var instr = instrIterator; var children = ImmutableArray.CreateBuilder(); @@ -88,11 +93,7 @@ public ImmutableArray Stackify(IBasicBlock basicBlock) } children.Reverse(); - var tree = instr switch - { - IValueInstruction vi => new TreeInstruction(vi, children.ToImmutable()), - _ => throw new InvalidOperationException(), - }; + var tree = new TreeInstruction(instr, children.ToImmutable()); return (tree, stopped); } } From 5b5cdb8b9fed410612994811b04a927c41db8224 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 14:53:11 +0200 Subject: [PATCH 40/55] Really basic stackification --- .../Internal/Codegen/CilCodegen.cs | 27 +++++++------------ .../OptimizingIr/Model/TreeInstruction.cs | 9 ++++--- .../Internal/OptimizingIr/Stackifier.cs | 5 ++++ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index e5c6dec53d..4c3d28f032 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -45,22 +45,7 @@ internal sealed class CilCodegen private readonly ImmutableDictionary allocatedLocals; private readonly ImmutableDictionary allocatedRegisters; private readonly Dictionary labels = new(); - - // NOTE: The current stackification attempt is FLAWED - // Imagine this situation: - // - // r1 := load loc0 - // r2 := box 1 as object - // store r1[0] := r2 - // - // We stackify it and get - // - // load loc0 - // box 1 as object - // store r1[0] - // - // OOPS! The index "leaked behind" the value, reversing the order - // We might need to structure the instructions in a tree after all + private readonly Stackifier stackifier; public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) { @@ -71,6 +56,7 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) var controlFlowBuilder = new ControlFlowBuilder(); this.InstructionEncoder = new InstructionEncoder(codeBuilder, controlFlowBuilder); + // TODO: Incorrect computations in case we stackify... this.allocatedLocals = procedure.Locals .Where(local => !SymbolEqualityComparer.Default.Equals(local.Type, IntrinsicSymbols.Unit)) .Select((local, index) => (Local: local, Index: index)) @@ -79,6 +65,8 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) .Where(reg => !SymbolEqualityComparer.Default.Equals(reg.Type, IntrinsicSymbols.Unit)) .Select((reg, index) => (Register: reg, Index: index)) .ToImmutableDictionary(pair => pair.Register, pair => this.allocatedLocals.Count + pair.Index); + + this.stackifier = new(procedure); } private UserStringHandle GetStringLiteralHandle(string text) => this.metadataCodegen.GetStringLiteralHandle(text); @@ -119,7 +107,12 @@ public void EncodeProcedure() private void EncodeBasicBlock(IBasicBlock basicBlock) { this.InstructionEncoder.MarkLabel(this.GetLabel(basicBlock)); - foreach (var instr in basicBlock.Instructions) this.EncodeInstruction(instr); + + var stackify = true; + var instructions = stackify + ? this.stackifier.Stackify(basicBlock) + : basicBlock.Instructions; + foreach (var instr in instructions) this.EncodeInstruction(instr); } private void EncodeInstruction(IInstruction instruction) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs index 619a7ee69c..217e68e7c6 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs @@ -16,7 +16,7 @@ internal sealed class TreeInstruction : InstructionBase, IOperand, IValueInstruc { public override string InstructionKeyword => this.Underlying.InstructionKeyword; - public Register Target => (this.Underlying as IValueInstruction)!.Target; + public Register Target => ((IValueInstruction)this.Underlying).Target; /// /// The original, non-tree instruction. @@ -37,8 +37,11 @@ public TreeInstruction(IInstruction underlying, ImmutableArray operand this.Operands = operands; } - public override string ToString() => $"{this.Target} := {this.ToOperandString()}"; - public string ToOperandString() => $"{this.InstructionKeyword}({string.Join(", ", this.Operands.Select(op => op.ToOperandString()))})"; + public override string ToString() => this.Underlying is IValueInstruction + ? $"{this.Target} := {this.ToOperandString()}" + : this.ToOperandString(); + public string ToOperandString() => + $"{this.InstructionKeyword}({string.Join(", ", this.Operands.Select(op => op.ToOperandString()))})"; public override IInstruction Clone() => new TreeInstruction(this.Underlying.Clone(), this.Operands.ToImmutableArray()); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs index 0c92466284..28d12bec7f 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -40,6 +40,11 @@ public Stackifier(IProcedure procedure) // TODO: Doc public ImmutableArray Stackify(IBasicBlock basicBlock) { + if (!this.procedure.BasicBlocks.Values.Contains(basicBlock)) + { + throw new ArgumentOutOfRangeException(nameof(basicBlock)); + } + var result = ImmutableArray.CreateBuilder(); var instr = basicBlock.LastInstruction; From b4bc28ea8ced96277384371fd8018d4ef855ca88 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 15:34:54 +0200 Subject: [PATCH 41/55] Nicer print --- .../OptimizingIr/Model/AddressOfInstruction.cs | 2 ++ .../Internal/OptimizingIr/Model/BoxInstruction.cs | 1 + .../Internal/OptimizingIr/Model/CallInstruction.cs | 1 + .../Internal/OptimizingIr/Model/IInstruction.cs | 6 ++++++ .../Internal/OptimizingIr/Model/InstructionBase.cs | 2 ++ .../OptimizingIr/Model/LoadFieldInstruction.cs | 1 + .../Internal/OptimizingIr/Model/LoadInstruction.cs | 2 ++ .../OptimizingIr/Model/MemberCallInstruction.cs | 1 + .../OptimizingIr/Model/NewArrayInstruction.cs | 1 + .../OptimizingIr/Model/NewObjectInstruction.cs | 1 + .../OptimizingIr/Model/StoreFieldInstruction.cs | 1 + .../Internal/OptimizingIr/Model/StoreInstruction.cs | 1 + .../Internal/OptimizingIr/Model/TreeInstruction.cs | 11 +++++++++-- 13 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs index 6b9c131f28..bc1ba23f1a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs @@ -21,6 +21,8 @@ internal sealed class AddressOfInstruction : InstructionBase, IValueInstruction /// public Symbol Source { get; set; } + public override IEnumerable StaticOperands => new[] { this.Source }; + public AddressOfInstruction(Register target, Symbol source) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs index 2bd2567c0a..dde2454169 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BoxInstruction.cs @@ -22,6 +22,7 @@ internal sealed class BoxInstruction : InstructionBase, IValueInstruction /// public IOperand Value { get; } + public override IEnumerable StaticOperands => new[] { this.BoxedType }; public override IEnumerable Operands => new[] { this.Value }; public BoxInstruction(Register target, TypeSymbol boxedType, IOperand value) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs index e57b7a25d4..b6abcdbc48 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/CallInstruction.cs @@ -23,6 +23,7 @@ internal sealed class CallInstruction : InstructionBase, IValueInstruction /// public IList Arguments { get; set; } = new List(); + public override IEnumerable StaticOperands => new[] { this.Procedure }; public override IEnumerable Operands => this.Arguments; public CallInstruction(Register target, FunctionSymbol procedure, IEnumerable arguments) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs index 73ead9eec7..95e6db005b 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IInstruction.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -42,6 +43,11 @@ internal interface IInstruction /// public IEnumerable JumpTargets { get; } + /// + /// The static operands of this instruction that are not runtime values. + /// + public IEnumerable StaticOperands { get; } + /// /// The input operands of this instruction. /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs index ac7cc64d94..a06186b2d5 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/InstructionBase.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; @@ -20,6 +21,7 @@ internal abstract class InstructionBase : IInstruction public virtual bool IsValidInUnreachableContext => false; public virtual IEnumerable JumpTargets => Enumerable.Empty(); IEnumerable IInstruction.JumpTargets => this.JumpTargets; + public virtual IEnumerable StaticOperands => Enumerable.Empty(); public virtual IEnumerable Operands => Enumerable.Empty(); public override abstract string ToString(); diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs index 1c30a2613b..339cd943f1 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadFieldInstruction.cs @@ -22,6 +22,7 @@ internal sealed class LoadFieldInstruction : InstructionBase, IValueInstruction /// public FieldSymbol Member { get; set; } + public override IEnumerable StaticOperands => new[] { this.Member }; public override IEnumerable Operands => new[] { this.Receiver }; public LoadFieldInstruction(Register target, IOperand receiver, FieldSymbol member) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs index 99ed4d0f15..c810c37bc8 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/LoadInstruction.cs @@ -17,6 +17,8 @@ internal sealed class LoadInstruction : InstructionBase, IValueInstruction /// public Symbol Source { get; set; } + public override IEnumerable StaticOperands => new[] { this.Source }; + public LoadInstruction(Register target, Symbol source) { this.Target = target; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs index 69c9fdfaf7..b9c776b2ea 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/MemberCallInstruction.cs @@ -28,6 +28,7 @@ internal sealed class MemberCallInstruction : InstructionBase, IValueInstruction /// public IList Arguments { get; set; } = new List(); + public override IEnumerable StaticOperands => new[] { this.Procedure }; public override IEnumerable Operands => this.Arguments.Prepend(this.Receiver); public MemberCallInstruction(Register target, FunctionSymbol procedure, IOperand receiver, IEnumerable arguments) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs index f9692f3a7e..1f2c5d1e5c 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewArrayInstruction.cs @@ -23,6 +23,7 @@ internal sealed class NewArrayInstruction : InstructionBase, IValueInstruction /// public IList Dimensions { get; set; } = new List(); + public override IEnumerable StaticOperands => new[] { this.ElementType }; public override IEnumerable Operands => this.Dimensions; public NewArrayInstruction(Register target, TypeSymbol elementType, IEnumerable dimensions) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs index 482007dbb9..8e654fef21 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NewObjectInstruction.cs @@ -23,6 +23,7 @@ internal sealed class NewObjectInstruction : InstructionBase, IValueInstruction /// public IList Arguments { get; set; } = new List(); + public override IEnumerable StaticOperands => new[] { this.Constructor }; public override IEnumerable Operands => this.Arguments; public NewObjectInstruction(Register target, FunctionSymbol constructor, IEnumerable arguments) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs index f286a2f798..93b1de01a2 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreFieldInstruction.cs @@ -25,6 +25,7 @@ internal sealed class StoreFieldInstruction : InstructionBase /// public IOperand Source { get; set; } + public override IEnumerable StaticOperands => new[] { this.Member }; public override IEnumerable Operands => new[] { this.Receiver, this.Source }; public StoreFieldInstruction(IOperand receiver, FieldSymbol member, IOperand source) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs index 597e5c29d0..51e23a98a0 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/StoreInstruction.cs @@ -20,6 +20,7 @@ internal sealed class StoreInstruction : InstructionBase /// public IOperand Source { get; set; } + public override IEnumerable StaticOperands => new[] { this.Target }; public override IEnumerable Operands => new[] { this.Source }; public StoreInstruction(Symbol target, IOperand source) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs index 217e68e7c6..4025806f3a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs @@ -25,6 +25,7 @@ internal sealed class TreeInstruction : InstructionBase, IOperand, IValueInstruc public override bool IsBranch => this.Underlying.IsBranch; public override IEnumerable JumpTargets => this.Underlying.JumpTargets.Cast(); + public override IEnumerable StaticOperands => this.Underlying.StaticOperands; public override IEnumerable Operands { get; } public TypeSymbol Type => this.Target.Type; @@ -40,8 +41,14 @@ public TreeInstruction(IInstruction underlying, ImmutableArray operand public override string ToString() => this.Underlying is IValueInstruction ? $"{this.Target} := {this.ToOperandString()}" : this.ToOperandString(); - public string ToOperandString() => - $"{this.InstructionKeyword}({string.Join(", ", this.Operands.Select(op => op.ToOperandString()))})"; + public string ToOperandString() + { + var staticOperands = this.StaticOperands.Select(op => op.FullName); + var operands = this.Operands.Select(op => op.ToOperandString()); + var jumpTargets = this.JumpTargets.Select(op => $"lbl{op.Index}"); + var allArgs = staticOperands.Concat(operands).Concat(jumpTargets); + return $"{this.InstructionKeyword}({string.Join(", ", allArgs)})"; + } public override IInstruction Clone() => new TreeInstruction(this.Underlying.Clone(), this.Operands.ToImmutableArray()); } From 5b12d73cb4fc6745f526226f4bdd371629306f60 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 16:23:32 +0200 Subject: [PATCH 42/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 4c3d28f032..799b74a47c 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -43,7 +43,7 @@ internal sealed class CilCodegen private readonly MetadataCodegen metadataCodegen; private readonly IProcedure procedure; private readonly ImmutableDictionary allocatedLocals; - private readonly ImmutableDictionary allocatedRegisters; + private readonly Dictionary allocatedRegisters = new(); private readonly Dictionary labels = new(); private readonly Stackifier stackifier; @@ -56,15 +56,10 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) var controlFlowBuilder = new ControlFlowBuilder(); this.InstructionEncoder = new InstructionEncoder(codeBuilder, controlFlowBuilder); - // TODO: Incorrect computations in case we stackify... this.allocatedLocals = procedure.Locals .Where(local => !SymbolEqualityComparer.Default.Equals(local.Type, IntrinsicSymbols.Unit)) .Select((local, index) => (Local: local, Index: index)) .ToImmutableDictionary(pair => pair.Local, pair => new AllocatedLocal(pair.Local, pair.Index)); - this.allocatedRegisters = procedure.Registers - .Where(reg => !SymbolEqualityComparer.Default.Equals(reg.Type, IntrinsicSymbols.Unit)) - .Select((reg, index) => (Register: reg, Index: index)) - .ToImmutableDictionary(pair => pair.Register, pair => this.allocatedLocals.Count + pair.Index); this.stackifier = new(procedure); } @@ -85,7 +80,12 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) private int? GetLocalIndex(LocalSymbol local) => this.GetAllocatedLocal(local)?.Index; private int? GetRegisterIndex(Register register) { - if (!this.allocatedRegisters.TryGetValue(register, out var allocatedRegister)) return null; + if (SymbolEqualityComparer.Default.Equals(register.Type, IntrinsicSymbols.Unit)) return null; + if (!this.allocatedRegisters.TryGetValue(register, out var allocatedRegister)) + { + allocatedRegister = this.allocatedRegisters.Count; + this.allocatedRegisters.Add(register, allocatedRegister); + } return allocatedRegister; } From 298a5431a17710cf8ed73daf9c468b180a75e2cb Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 16:47:14 +0200 Subject: [PATCH 43/55] Update CilCodegen.cs --- .../Internal/Codegen/CilCodegen.cs | 109 +++++++++++------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 799b74a47c..13e45f2149 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -46,6 +46,7 @@ internal sealed class CilCodegen private readonly Dictionary allocatedRegisters = new(); private readonly Dictionary labels = new(); private readonly Stackifier stackifier; + private int treeDepth; public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) { @@ -117,6 +118,20 @@ private void EncodeBasicBlock(IBasicBlock basicBlock) private void EncodeInstruction(IInstruction instruction) { + var operandEnumerator = instruction.Operands.GetEnumerator(); + IOperand NextOperand() + { + if (!operandEnumerator!.MoveNext()) throw new InvalidOperationException(); + return operandEnumerator.Current; + } + IEnumerable RemainingOperands() + { + while (operandEnumerator!.MoveNext()) yield return operandEnumerator.Current; + } + + // NOTE: Unwrap after capturing operands + if (instruction is TreeInstruction treeInstr) instruction = treeInstr.Underlying; + switch (instruction) { case OptimizingIr.Model.SequencePoint sp: @@ -150,7 +165,7 @@ private void EncodeInstruction(IInstruction instruction) } case BranchInstruction branch: { - this.EncodePush(branch.Condition); + this.EncodePush(NextOperand()); var then = this.GetLabel(branch.Then); var @else = this.GetLabel(branch.Else); this.InstructionEncoder.Branch(ILOpCode.Brtrue, then); @@ -159,14 +174,14 @@ private void EncodeInstruction(IInstruction instruction) } case RetInstruction ret: { - this.EncodePush(ret.Value); + this.EncodePush(NextOperand()); this.InstructionEncoder.OpCode(ILOpCode.Ret); break; } case ArithmeticInstruction arithmetic: { - this.EncodePush(arithmetic.Left); - this.EncodePush(arithmetic.Right); + this.EncodePush(NextOperand()); + this.EncodePush(NextOperand()); this.InstructionEncoder.OpCode(arithmetic.Op switch { ArithmeticOp.Add => ILOpCode.Add, @@ -178,7 +193,7 @@ private void EncodeInstruction(IInstruction instruction) ArithmeticOp.Equal => ILOpCode.Ceq, _ => throw new InvalidOperationException(), }); - this.StoreLocal(arithmetic.Target); + this.StoreRegister(arithmetic.Target); break; } case LoadInstruction load: @@ -207,15 +222,15 @@ private void EncodeInstruction(IInstruction instruction) throw new InvalidOperationException(); } // Just copy to the target local - this.StoreLocal(load.Target); + this.StoreRegister(load.Target); break; } case LoadElementInstruction loadElement: { // Array - this.EncodePush(loadElement.Array); + this.EncodePush(NextOperand()); // Indices - foreach (var i in loadElement.Indices) this.EncodePush(i); + foreach (var i in RemainingOperands()) this.EncodePush(i); // One-dimensional and multi-dimensional arrays are very different if (loadElement.Indices.Count == 1) { @@ -232,15 +247,15 @@ private void EncodeInstruction(IInstruction instruction) loadElement.Indices.Count)); } // Store result - this.StoreLocal(loadElement.Target); + this.StoreRegister(loadElement.Target); break; } case LoadFieldInstruction loadField: { - this.EncodePush(loadField.Receiver); + this.EncodePush(NextOperand()); this.InstructionEncoder.OpCode(ILOpCode.Ldfld); this.InstructionEncoder.Token(this.GetHandle(loadField.Member)); - this.StoreLocal(loadField.Target); + this.StoreRegister(loadField.Target); break; } case StoreInstruction store: @@ -250,11 +265,11 @@ private void EncodeInstruction(IInstruction instruction) case ParameterSymbol: throw new InvalidOperationException(); case LocalSymbol local: - this.EncodePush(store.Source); + this.EncodePush(NextOperand()); this.StoreLocal(local); break; case GlobalSymbol global: - this.EncodePush(store.Source); + this.EncodePush(NextOperand()); this.InstructionEncoder.OpCode(ILOpCode.Stsfld); this.EncodeToken(global); break; @@ -265,9 +280,10 @@ private void EncodeInstruction(IInstruction instruction) } case StoreElementInstruction storeElement: { - this.EncodePush(storeElement.TargetArray); - foreach (var index in storeElement.Indices) this.EncodePush(index); - this.EncodePush(storeElement.Source); + this.EncodePush(NextOperand()); + var remainingOps = RemainingOperands(); + foreach (var index in remainingOps.SkipLast(1)) this.EncodePush(index); + this.EncodePush(remainingOps.Last()); // TODO: Not the prettiest... var targetStorageType = storeElement.TargetArray.Type!.Substitution.GenericArguments[0].Substitution; @@ -290,8 +306,8 @@ private void EncodeInstruction(IInstruction instruction) } case StoreFieldInstruction storeField: { - this.EncodePush(storeField.Receiver); - this.EncodePush(storeField.Source); + this.EncodePush(NextOperand()); + this.EncodePush(NextOperand()); this.InstructionEncoder.OpCode(ILOpCode.Stfld); this.InstructionEncoder.Token(this.GetHandle(storeField.Member)); break; @@ -304,7 +320,7 @@ private void EncodeInstruction(IInstruction instruction) { var paramIndex = this.GetParameterIndex(param); this.InstructionEncoder.LoadArgumentAddress(paramIndex); - this.StoreLocal(addressOf.Target); + this.StoreRegister(addressOf.Target); break; } case LocalSymbol local: @@ -313,14 +329,14 @@ private void EncodeInstruction(IInstruction instruction) // NOTE: What if we ask the address of a unit? Debug.Assert(localIndex is not null); this.InstructionEncoder.LoadLocalAddress(localIndex.Value); - this.StoreLocal(addressOf.Target); + this.StoreRegister(addressOf.Target); break; } case GlobalSymbol global: { this.InstructionEncoder.OpCode(ILOpCode.Ldsflda); this.EncodeToken(global); - this.StoreLocal(addressOf.Target); + this.StoreRegister(addressOf.Target); break; } default: @@ -331,41 +347,41 @@ private void EncodeInstruction(IInstruction instruction) case CallInstruction call: { // Arguments - foreach (var arg in call.Arguments) this.EncodePush(arg); + foreach (var arg in RemainingOperands()) this.EncodePush(arg); // Call this.InstructionEncoder.OpCode(ILOpCode.Call); this.EncodeToken(call.Procedure); // Store result - this.StoreLocal(call.Target); + this.StoreRegister(call.Target); break; } case MemberCallInstruction mcall: { // Receiver - this.EncodePush(mcall.Receiver); + this.EncodePush(NextOperand()); // Arguments - foreach (var arg in mcall.Arguments) this.EncodePush(arg); + foreach (var arg in RemainingOperands()) this.EncodePush(arg); // Call this.InstructionEncoder.OpCode(mcall.Procedure.IsVirtual ? ILOpCode.Callvirt : ILOpCode.Call); this.EncodeToken(mcall.Procedure); // Store result - this.StoreLocal(mcall.Target); + this.StoreRegister(mcall.Target); break; } case NewObjectInstruction newObj: { // Arguments - foreach (var arg in newObj.Arguments) this.EncodePush(arg); + foreach (var arg in RemainingOperands()) this.EncodePush(arg); this.InstructionEncoder.OpCode(ILOpCode.Newobj); this.EncodeToken(newObj.Constructor); // Store result - this.StoreLocal(newObj.Target); + this.StoreRegister(newObj.Target); break; } case NewArrayInstruction newArr: { // Dimensions - foreach (var dim in newArr.Dimensions) this.EncodePush(dim); + foreach (var dim in RemainingOperands()) this.EncodePush(dim); // One-dimensional and multi-dimensional arrays are very different if (newArr.Dimensions.Count == 1) { @@ -382,30 +398,30 @@ private void EncodeInstruction(IInstruction instruction) newArr.Dimensions.Count)); } // Store result - this.StoreLocal(newArr.Target); + this.StoreRegister(newArr.Target); break; } case ArrayLengthInstruction arrLen: { // Array - this.EncodePush(arrLen.Array); + this.EncodePush(NextOperand()); // Length query this.InstructionEncoder.OpCode(ILOpCode.Ldlen); // Convert to I4 this.InstructionEncoder.OpCode(ILOpCode.Conv_i4); // Store result - this.StoreLocal(arrLen.Target); + this.StoreRegister(arrLen.Target); break; } case BoxInstruction box: { // Value to be boxed - this.EncodePush(box.Value); + this.EncodePush(NextOperand()); // Box it this.InstructionEncoder.OpCode(ILOpCode.Box); this.EncodeToken(box.Value.Type!); // Store result - this.StoreLocal(box.Target); + this.StoreRegister(box.Target); break; } default: @@ -423,8 +439,13 @@ private void EncodePush(IOperand operand) { switch (operand) { + case TreeInstruction treeInstruction: + ++this.treeDepth; + this.EncodeInstruction(treeInstruction); + --this.treeDepth; + break; case Void: - return; + break; case Register r: this.LoadRegister(r); break; @@ -450,30 +471,32 @@ private void EncodePush(IOperand operand) } } - private void LoadLocal(LocalSymbol local) + private void LoadRegister(Register register) { - var index = this.GetLocalIndex(local); + var index = this.GetRegisterIndex(register); if (index is null) return; this.InstructionEncoder.LoadLocal(index.Value); } - private void LoadRegister(Register register) + private void StoreRegister(Register register) { + if (this.treeDepth > 0) return; + var index = this.GetRegisterIndex(register); if (index is null) return; - this.InstructionEncoder.LoadLocal(index.Value); + this.InstructionEncoder.StoreLocal(index.Value); } - private void StoreLocal(LocalSymbol local) + private void LoadLocal(LocalSymbol local) { var index = this.GetLocalIndex(local); if (index is null) return; - this.InstructionEncoder.StoreLocal(index.Value); + this.InstructionEncoder.LoadLocal(index.Value); } - private void StoreLocal(Register register) + private void StoreLocal(LocalSymbol local) { - var index = this.GetRegisterIndex(register); + var index = this.GetLocalIndex(local); if (index is null) return; this.InstructionEncoder.StoreLocal(index.Value); } From 5588b096af6edfb62b0fd4f74638c7fad53a2411 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 17:02:28 +0200 Subject: [PATCH 44/55] Stackification works --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 5 +++-- .../Internal/OptimizingIr/Model/BranchInstruction.cs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 13e45f2149..81c76da2a9 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -84,7 +84,8 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) if (SymbolEqualityComparer.Default.Equals(register.Type, IntrinsicSymbols.Unit)) return null; if (!this.allocatedRegisters.TryGetValue(register, out var allocatedRegister)) { - allocatedRegister = this.allocatedRegisters.Count; + // NOTE: We need to offset by the number of locals + allocatedRegister = this.allocatedLocals.Count + this.allocatedRegisters.Count; this.allocatedRegisters.Add(register, allocatedRegister); } return allocatedRegister; @@ -281,7 +282,7 @@ IEnumerable RemainingOperands() case StoreElementInstruction storeElement: { this.EncodePush(NextOperand()); - var remainingOps = RemainingOperands(); + var remainingOps = RemainingOperands().ToList(); foreach (var index in remainingOps.SkipLast(1)) this.EncodePush(index); this.EncodePush(remainingOps.Last()); diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs index 2389ce853e..1b88bff0c5 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs @@ -10,6 +10,7 @@ internal sealed class BranchInstruction : InstructionBase { public override string InstructionKeyword => "jump_if"; public override bool IsBranch => true; + public override IEnumerable Operands => new[] { this.Condition }; public override IEnumerable JumpTargets => new[] { this.Then, this.Else }; /// From d2aaa51bff275d2638ba11b5eab7a5e5bc360ece Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Thu, 12 Oct 2023 17:33:31 +0200 Subject: [PATCH 45/55] Removed unused regs --- .../Internal/Codegen/CilCodegen.cs | 11 ++++++++++- .../Internal/OptimizingIr/Stackifier.cs | 17 ++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index 81c76da2a9..e5066afd06 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -82,6 +82,7 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure) private int? GetRegisterIndex(Register register) { if (SymbolEqualityComparer.Default.Equals(register.Type, IntrinsicSymbols.Unit)) return null; + if (this.stackifier.RegisterUses[register] == 0) return null; if (!this.allocatedRegisters.TryGetValue(register, out var allocatedRegister)) { // NOTE: We need to offset by the number of locals @@ -484,7 +485,15 @@ private void StoreRegister(Register register) if (this.treeDepth > 0) return; var index = this.GetRegisterIndex(register); - if (index is null) return; + if (index is null) + { + if (!SymbolEqualityComparer.Default.Equals(register.Type, IntrinsicSymbols.Unit)) + { + // Need to pop + this.InstructionEncoder.OpCode(ILOpCode.Pop); + } + return; + } this.InstructionEncoder.StoreLocal(index.Value); } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs index 28d12bec7f..a2623dae27 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -26,18 +26,25 @@ private static ImmutableDictionary CountRegisterUses(IEnumerable< return registerUses.ToImmutable(); } + /// + /// A dictionary for the number of register uses for each register. + /// + public ImmutableDictionary RegisterUses { get; } + private readonly IProcedure procedure; - private readonly ImmutableDictionary registerUses; public Stackifier(IProcedure procedure) { this.procedure = procedure; var instructions = procedure.BasicBlocks.Values.SelectMany(bb => bb.Instructions); - // Count the number of register uses - this.registerUses = CountRegisterUses(instructions); + this.RegisterUses = CountRegisterUses(instructions); } - // TODO: Doc + /// + /// Stackifies the given basic block. + /// + /// The basic block to stackify. + /// The new, stackified array of instructions. public ImmutableArray Stackify(IBasicBlock basicBlock) { if (!this.procedure.BasicBlocks.Values.Contains(basicBlock)) @@ -80,7 +87,7 @@ public ImmutableArray Stackify(IBasicBlock basicBlock) // If we have a single-use register as a result immediately before this instruction, // all good, part of the tree if (!stopped - && this.registerUses[reg] == 1 + && this.RegisterUses[reg] == 1 && instrIterator.Prev is IValueInstruction valueInstr && valueInstr.Target == reg) { From e77ece9477c9ade5637a5102a51fb2ab25ff1021 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 09:24:59 +0200 Subject: [PATCH 46/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index e5066afd06..bf5c3da13a 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -19,6 +19,9 @@ namespace Draco.Compiler.Internal.Codegen; /// internal sealed class CilCodegen { + // NOTE: We might want to expose this as a setting later for debugging + const bool stackify = true; + /// /// The instruction encoder. /// @@ -110,8 +113,6 @@ public void EncodeProcedure() private void EncodeBasicBlock(IBasicBlock basicBlock) { this.InstructionEncoder.MarkLabel(this.GetLabel(basicBlock)); - - var stackify = true; var instructions = stackify ? this.stackifier.Stackify(basicBlock) : basicBlock.Instructions; From bf5fe11fba54f3ba9ae021e45d98865a4d77fcc6 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 09:37:19 +0200 Subject: [PATCH 47/55] Update CilCodegen.cs --- src/Draco.Compiler/Internal/Codegen/CilCodegen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs index bf5c3da13a..6b36474828 100644 --- a/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/CilCodegen.cs @@ -20,7 +20,7 @@ namespace Draco.Compiler.Internal.Codegen; internal sealed class CilCodegen { // NOTE: We might want to expose this as a setting later for debugging - const bool stackify = true; + private const bool stackify = true; /// /// The instruction encoder. From bcaa9bcbb7bd50cc8f4baca8d526786de68dfa6a Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 09:39:48 +0200 Subject: [PATCH 48/55] Cleanup --- src/Draco.Compiler.Benchmarks/SyntaxBenchmarks.cs | 1 - src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs | 1 - .../Internal/OptimizingIr/Model/AddressOfInstruction.cs | 4 ---- .../Internal/OptimizingIr/Model/BranchInstruction.cs | 1 - src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs | 3 --- .../Internal/OptimizingIr/Model/IValueInstruction.cs | 6 ------ .../Internal/OptimizingIr/Model/JumpInstruction.cs | 1 - .../Internal/OptimizingIr/Model/NopInstruction.cs | 3 --- .../Internal/OptimizingIr/Model/SequencePoint.cs | 2 -- .../Internal/OptimizingIr/Model/TreeInstruction.cs | 2 -- src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs | 2 -- .../Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs | 1 - .../Internal/Symbols/Metadata/TypeProvider.cs | 2 -- src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs | 6 ------ 14 files changed, 35 deletions(-) diff --git a/src/Draco.Compiler.Benchmarks/SyntaxBenchmarks.cs b/src/Draco.Compiler.Benchmarks/SyntaxBenchmarks.cs index 2f79cc3070..f405370564 100644 --- a/src/Draco.Compiler.Benchmarks/SyntaxBenchmarks.cs +++ b/src/Draco.Compiler.Benchmarks/SyntaxBenchmarks.cs @@ -3,7 +3,6 @@ using BenchmarkDotNet.Attributes; using Draco.Compiler.Api.Syntax; using Draco.Compiler.Internal.Syntax; -using CompilationUnitSyntax = Draco.Compiler.Internal.Syntax.CompilationUnitSyntax; using SyntaxToken = Draco.Compiler.Internal.Syntax.SyntaxToken; namespace Draco.Compiler.Benchmarks; diff --git a/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs b/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs index 394227883f..fbba4e7f6f 100644 --- a/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs +++ b/src/Draco.Compiler/Internal/Codegen/AllocatedLocal.cs @@ -1,4 +1,3 @@ -using Draco.Compiler.Internal.OptimizingIr.Model; using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.Codegen; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs index bc1ba23f1a..5c548d47e3 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/AddressOfInstruction.cs @@ -1,8 +1,4 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs index 1b88bff0c5..1daa1b8e19 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/BranchInstruction.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace Draco.Compiler.Internal.OptimizingIr.Model; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs index a5743c2c6b..a407ff6553 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/EndScope.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - namespace Draco.Compiler.Internal.OptimizingIr.Model; /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs index 7d4baff395..6d9979cd6b 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IValueInstruction.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Draco.Compiler.Internal.OptimizingIr.Model; /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs index 673bcadcfe..9d1f1afbe8 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/JumpInstruction.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace Draco.Compiler.Internal.OptimizingIr.Model; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs index 462f172244..e4fd4a17cb 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/NopInstruction.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - namespace Draco.Compiler.Internal.OptimizingIr.Model; /// diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs index 1fcb691134..f805888a02 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/SequencePoint.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Linq; using System.Text; using Draco.Compiler.Api.Syntax; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs index 4025806f3a..8309594d6c 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/TreeInstruction.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Draco.Compiler.Internal.Symbols; namespace Draco.Compiler.Internal.OptimizingIr.Model; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs index a2623dae27..be8e6df96a 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Stackifier.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Draco.Compiler.Internal.OptimizingIr.Model; namespace Draco.Compiler.Internal.OptimizingIr; diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs index eb68a30d31..7fa3cc852a 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticFieldSymbol.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Metadata; diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs index d9cab6d921..f8b4093b01 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs @@ -1,9 +1,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Reflection; using System.Reflection.Metadata; -using System.Reflection.PortableExecutable; using Draco.Compiler.Api; using Draco.Compiler.Internal.Symbols.Synthetized; diff --git a/src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs index fb2b3c98f5..3c76eb6933 100644 --- a/src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/ReferenceTypeSymbol.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Draco.Compiler.Internal.Symbols; /// From bb68005823cf2a5ff3ccdc79450906349542fc3d Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 09:58:54 +0200 Subject: [PATCH 49/55] Update FunctionBodyCodegen.cs --- .../OptimizingIr/FunctionBodyCodegen.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index beaf90e55a..a41ba6ca74 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -13,6 +13,9 @@ namespace Draco.Compiler.Internal.OptimizingIr; +// TODO: Operators and calls became identical, can we merge them? +// During lowering we could turn operators into calls + /// /// Generates IR code on function-local level. /// @@ -272,21 +275,28 @@ public override IOperand VisitSequencePointExpression(BoundSequencePointExpressi public override IOperand VisitCallExpression(BoundCallExpression node) { - // TODO: Lots of duplication, we should merge these instructions... var receiver = this.CompileReceiver(node); var args = node.Arguments .Zip(node.Method.Parameters) .Select(pair => this.BoxIfNeeded(pair.Second.Type, this.Compile(pair.First))) - .ToList(); + .ToImmutableArray(); var callResult = this.DefineRegister(node.TypeRequired); - var proc = this.TranslateFunctionSymbol(node.Method); - if (receiver is null) + + if (node.Method is IrFunctionSymbol irFunc) { - this.Write(Call(callResult, proc, args)); + irFunc.Codegen(this, callResult, args); } else { - this.Write(MemberCall(callResult, proc, receiver, args)); + var proc = this.TranslateFunctionSymbol(node.Method); + if (receiver is null) + { + this.Write(Call(callResult, proc, args)); + } + else + { + this.Write(MemberCall(callResult, proc, receiver, args)); + } } return callResult; } @@ -397,7 +407,7 @@ public override IOperand VisitAssignmentExpression(BoundAssignmentExpression nod } else { - // TOO + // TODO throw new System.NotImplementedException(); } } From bc5d4cee087c4990e2bacdb92a5b0bf57dcddded Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 10:52:22 +0200 Subject: [PATCH 50/55] Lowered unary and binary nodes --- .../Internal/Lowering/LocalRewriter.cs | 38 +++++++++++++- .../OptimizingIr/FunctionBodyCodegen.cs | 51 +++---------------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs b/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs index 92444094a1..1888e2289b 100644 --- a/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs +++ b/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs @@ -47,6 +47,41 @@ private BoundLiteralExpression LiteralExpression(object? value) return BoundTreeFactory.LiteralExpression(value, literalType); } + public override BoundNode VisitUnaryExpression(BoundUnaryExpression node) + { + // Unary operators simply get turned into calls, as they use practically the same logic + // + // @ x + // + // => + // + // @(x) + + var arg = (BoundExpression)node.Operand.Accept(this); + return CallExpression( + receiver: null, + method: node.Operator, + arguments: ImmutableArray.Create(arg)); + } + + public override BoundNode VisitBinaryExpression(BoundBinaryExpression node) + { + // Binary operators simply get turned into calls, as they use practically the same logic + // + // x @ y + // + // => + // + // @(x, y) + + var left = (BoundExpression)node.Left.Accept(this); + var right = (BoundExpression)node.Right.Accept(this); + return CallExpression( + receiver: null, + method: node.Operator, + arguments: ImmutableArray.Create(left, right)); + } + public override BoundNode VisitCallExpression(BoundCallExpression node) { if (!node.Method.IsVariadic) return base.VisitCallExpression(node); @@ -309,11 +344,12 @@ public override BoundNode VisitRelationalExpression(BoundRelationalExpression no { var left = (BoundExpression)node.First.Accept(this); var right = (BoundExpression)node.Comparisons[0].Next.Accept(this); - return BinaryExpression( + var result = BinaryExpression( left: left, @operator: node.Comparisons[0].Operator, right: right, type: this.IntrinsicSymbols.Bool); + return result.Accept(this); } // expr1 < expr2 == expr3 > expr4 != ... diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index a41ba6ca74..a6d57cad5c 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -455,43 +455,6 @@ private void PatchStoreSource(IInstruction storeInstr, TypeSymbol targetType, IO } } - public override IOperand VisitUnaryExpression(BoundUnaryExpression node) - { - var sub = node.Operand.Accept(this); - var target = this.DefineRegister(node.TypeRequired); - - if (node.Operator is IrFunctionSymbol irFunction) - { - irFunction.Codegen(this, target, ImmutableArray.Create(sub)); - } - else - { - // TODO - throw new System.NotImplementedException(); - } - - return target; - } - - public override IOperand VisitBinaryExpression(BoundBinaryExpression node) - { - var left = this.Compile(node.Left); - var right = this.Compile(node.Right); - var target = this.DefineRegister(node.TypeRequired); - - if (node.Operator is IrFunctionSymbol irFunction) - { - irFunction.Codegen(this, target, ImmutableArray.Create(left, right)); - } - else - { - // TODO - throw new System.NotImplementedException(); - } - - return target; - } - public override IOperand VisitReturnExpression(BoundReturnExpression node) { var operand = this.Compile(node.Value); @@ -554,7 +517,8 @@ private FunctionInstanceSymbol TranslateFunctionInstanceSymbol(FunctionInstanceS return i; } - public override IOperand VisitLiteralExpression(BoundLiteralExpression node) => new Constant(node.Value, node.TypeRequired); + public override IOperand VisitLiteralExpression(BoundLiteralExpression node) => + new Constant(node.Value, node.TypeRequired); public override IOperand VisitUnitExpression(BoundUnitExpression node) => default(Void); public override IOperand VisitFieldExpression(BoundFieldExpression node) @@ -565,12 +529,11 @@ public override IOperand VisitFieldExpression(BoundFieldExpression node) return result; } - private static MetadataFieldSymbol? ExtractMetadataField(FieldSymbol field) => field switch - { - MetadataFieldSymbol m => m, - FieldInstanceSymbol i => ExtractMetadataField(i.GenericDefinition), - _ => null, - }; + public override IOperand VisitUnaryExpression(BoundUnaryExpression node) => + throw new System.InvalidOperationException(); + + public override IOperand VisitBinaryExpression(BoundBinaryExpression node) => + throw new System.InvalidOperationException(); private static MetadataStaticFieldSymbol? ExtractMetadataStaticField(GlobalSymbol global) => global switch { From ffa2a739fd627e34410065e8c18705951c812658 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 12:00:48 +0200 Subject: [PATCH 51/55] Fix --- .../OptimizingIr/FunctionBodyCodegen.cs | 13 ++- .../Symbols/Metadata/MetadataSymbol.cs | 2 +- .../Synthetized/DelegateIrFunctionSymbol.cs | 90 +++++++++++++++++++ .../Synthetized/IntrinsicFunctionSymbol.cs | 51 +---------- .../Symbols/Synthetized/IntrinsicSymbols.cs | 6 +- .../Symbols/Synthetized/IrFunctionSymbol.cs | 16 +--- ...s => MetadataConstructorFunctionSymbol.cs} | 38 ++++---- 7 files changed, 131 insertions(+), 85 deletions(-) create mode 100644 src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs rename src/Draco.Compiler/Internal/Symbols/Synthetized/{SynthetizedMetadataConstructorSymbol.cs => MetadataConstructorFunctionSymbol.cs} (78%) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index a6d57cad5c..043c75769b 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -282,13 +282,14 @@ public override IOperand VisitCallExpression(BoundCallExpression node) .ToImmutableArray(); var callResult = this.DefineRegister(node.TypeRequired); - if (node.Method is IrFunctionSymbol irFunc) + var proc = this.TranslateFunctionSymbol(node.Method); + var irFunc = ExtractIrFunction(proc); + if (irFunc is not null) { irFunc.Codegen(this, callResult, args); } else { - var proc = this.TranslateFunctionSymbol(node.Method); if (receiver is null) { this.Write(Call(callResult, proc, args)); @@ -507,6 +508,7 @@ public override IOperand VisitFunctionGroupExpression(BoundFunctionGroupExpressi SynthetizedFunctionSymbol func => this.SynthetizeProcedure(func).Symbol, MetadataMethodSymbol m => m, FunctionInstanceSymbol i => this.TranslateFunctionInstanceSymbol(i), + IrFunctionSymbol i => i, _ => throw new System.ArgumentOutOfRangeException(nameof(symbol)), }; @@ -541,4 +543,11 @@ public override IOperand VisitBinaryExpression(BoundBinaryExpression node) => // TODO: Global instances? _ => null, }; + + private static IrFunctionSymbol? ExtractIrFunction(FunctionSymbol symbol) => symbol switch + { + IrFunctionSymbol i => i, + FunctionInstanceSymbol i => ExtractIrFunction(i.GenericDefinition), + _ => null, + }; } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs index 376a45b8fb..e3af4ac367 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs @@ -108,7 +108,7 @@ public static IEnumerable ToSymbol( private static FunctionSymbol SynthetizeConstructor( MetadataTypeSymbol type, - MethodDefinition ctorMethod) => new SynthetizedMetadataConstructorSymbol(type, ctorMethod); + MethodDefinition ctorMethod) => new MetadataConstructorFunctionSymbol(type, ctorMethod); /// /// Gets the documentation XML as text for the given . diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs new file mode 100644 index 0000000000..ed4181538d --- /dev/null +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Draco.Compiler.Api.Syntax; + +namespace Draco.Compiler.Internal.Symbols.Synthetized; + +/// +/// An backed by a delegate. +/// +internal sealed class DelegateIrFunctionSymbol : IrFunctionSymbol +{ + /// + /// Constructs a function symbol for an unary operator. + /// + /// The for the unary operator. + /// The operand type. + /// The return type. + /// The code generation function. + /// The constructed function symbol. + public static FunctionSymbol UnaryOperator( + TokenKind token, + TypeSymbol operandType, + TypeSymbol returnType, + CodegenDelegate codegen) => + new DelegateIrFunctionSymbol(GetUnaryOperatorName(token), new[] { operandType }, returnType, codegen); + + /// + /// Constructs a function symbol for a binary operator. + /// + /// The for the binary operator. + /// The left operand type. + /// The right operand type. + /// The return type. + /// The code generation function. + /// The constructed function symbol. + public static FunctionSymbol BinaryOperator( + TokenKind token, + TypeSymbol leftType, + TypeSymbol rightType, + TypeSymbol returnType, + CodegenDelegate codegen) => + new DelegateIrFunctionSymbol(GetBinaryOperatorName(token), new[] { leftType, rightType }, returnType, codegen); + + /// + /// Constructs a function symbol for a comparison operator. + /// + /// The for the comparison operator. + /// The left operand type. + /// The right operand type. + /// The return type of the comparison. + /// The code generation function. + /// The constructed function symbol. + public static FunctionSymbol ComparisonOperator( + TokenKind token, + TypeSymbol leftType, + TypeSymbol rightType, + TypeSymbol returnType, + CodegenDelegate codegen) => + new DelegateIrFunctionSymbol(GetComparisonOperatorName(token), new[] { leftType, rightType }, returnType, codegen); + + public override ImmutableArray Parameters { get; } + + public override TypeSymbol ReturnType { get; } + public override Symbol? ContainingSymbol => null; + public override bool IsSpecialName => true; + public override bool IsStatic => true; + + public override string Name { get; } + + public override CodegenDelegate Codegen { get; } + + public DelegateIrFunctionSymbol( + string name, + IEnumerable paramTypes, + TypeSymbol returnType, + CodegenDelegate codegen) + { + this.Name = name; + this.Parameters = paramTypes + .Select(t => new SynthetizedParameterSymbol(this, t)) + .Cast() + .ToImmutableArray(); + this.ReturnType = returnType; + this.Codegen = codegen; + } +} diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs index 8f557f4e63..52a0be4a3c 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs @@ -8,57 +8,8 @@ namespace Draco.Compiler.Internal.Symbols.Synthetized; /// /// A function intrinsic known by the compiler. This function has no implementation, as it is known by the compiler. /// -internal class IntrinsicFunctionSymbol : FunctionSymbol +internal sealed class IntrinsicFunctionSymbol : FunctionSymbol { - /// - /// Constructs a function symbol for an unary operator. - /// - /// The for the unary operator. - /// The operand type. - /// The return type. - /// The code generation function. - /// The constructed function symbol. - public static FunctionSymbol UnaryOperator( - TokenKind token, - TypeSymbol operandType, - TypeSymbol returnType, - IrFunctionSymbol.CodegenDelegate codegen) => - new IrFunctionSymbol(GetUnaryOperatorName(token), new[] { operandType }, returnType, codegen); - - /// - /// Constructs a function symbol for a binary operator. - /// - /// The for the binary operator. - /// The left operand type. - /// The right operand type. - /// The return type. - /// The code generation function. - /// The constructed function symbol. - public static FunctionSymbol BinaryOperator( - TokenKind token, - TypeSymbol leftType, - TypeSymbol rightType, - TypeSymbol returnType, - IrFunctionSymbol.CodegenDelegate codegen) => - new IrFunctionSymbol(GetBinaryOperatorName(token), new[] { leftType, rightType }, returnType, codegen); - - /// - /// Constructs a function symbol for a comparison operator. - /// - /// The for the comparison operator. - /// The left operand type. - /// The right operand type. - /// The return type of the comparison. - /// The code generation function. - /// The constructed function symbol. - public static FunctionSymbol ComparisonOperator( - TokenKind token, - TypeSymbol leftType, - TypeSymbol rightType, - TypeSymbol returnType, - IrFunctionSymbol.CodegenDelegate codegen) => - new IrFunctionSymbol(GetComparisonOperatorName(token), new[] { leftType, rightType }, returnType, codegen); - public override ImmutableArray Parameters { get; } public override TypeSymbol ReturnType { get; } diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicSymbols.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicSymbols.cs index 2a0b795913..01572e28f5 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicSymbols.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicSymbols.cs @@ -116,20 +116,20 @@ private FunctionSymbol Unary( TypeSymbol operandType, TypeSymbol returnType, IrFunctionSymbol.CodegenDelegate codegen) => - IntrinsicFunctionSymbol.UnaryOperator(token, operandType, returnType, codegen); + DelegateIrFunctionSymbol.UnaryOperator(token, operandType, returnType, codegen); private FunctionSymbol Binary( TokenKind token, TypeSymbol leftType, TypeSymbol rightType, TypeSymbol returnType, IrFunctionSymbol.CodegenDelegate codegen) => - IntrinsicFunctionSymbol.BinaryOperator(token, leftType, rightType, returnType, codegen); + DelegateIrFunctionSymbol.BinaryOperator(token, leftType, rightType, returnType, codegen); private FunctionSymbol Comparison( TokenKind token, TypeSymbol leftType, TypeSymbol rightType, IrFunctionSymbol.CodegenDelegate codegen) => - IntrinsicFunctionSymbol.ComparisonOperator(token, leftType, rightType, this.Bool, codegen); + DelegateIrFunctionSymbol.ComparisonOperator(token, leftType, rightType, this.Bool, codegen); // Codegen diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs index 8c166afcb4..ce198d6d89 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs @@ -6,9 +6,9 @@ namespace Draco.Compiler.Internal.Symbols.Synthetized; /// -/// An that provides its IR codegen. +/// An intrinsic that provides its IR codegen. /// -internal sealed class IrFunctionSymbol : IntrinsicFunctionSymbol +internal abstract class IrFunctionSymbol : FunctionSymbol { /// /// The codegen delegate. @@ -24,15 +24,5 @@ public delegate void CodegenDelegate( /// /// The codegen function. /// - public CodegenDelegate Codegen { get; } - - public IrFunctionSymbol( - string name, - IEnumerable paramTypes, - TypeSymbol returnType, - CodegenDelegate codegen) - : base(name, paramTypes, returnType) - { - this.Codegen = codegen; - } + public abstract CodegenDelegate Codegen { get; } } diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/SynthetizedMetadataConstructorSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataConstructorFunctionSymbol.cs similarity index 78% rename from src/Draco.Compiler/Internal/Symbols/Synthetized/SynthetizedMetadataConstructorSymbol.cs rename to src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataConstructorFunctionSymbol.cs index 9407c69137..a9de701c2f 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/SynthetizedMetadataConstructorSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataConstructorFunctionSymbol.cs @@ -1,20 +1,27 @@ +using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Linq.Expressions; using System.Reflection.Metadata; +using System.Text; +using System.Threading.Tasks; using Draco.Compiler.Internal.BoundTree; using Draco.Compiler.Internal.Symbols.Generic; using Draco.Compiler.Internal.Symbols.Metadata; -using static Draco.Compiler.Internal.BoundTree.BoundTreeFactory; +using static Draco.Compiler.Internal.OptimizingIr.InstructionFactory; namespace Draco.Compiler.Internal.Symbols.Synthetized; /// -/// A synthetized constructor function for metadata types. +/// A constructor function for a metadata type. /// -internal sealed class SynthetizedMetadataConstructorSymbol : SynthetizedFunctionSymbol +internal sealed class MetadataConstructorFunctionSymbol : IrFunctionSymbol { public override string Name => this.instantiatedType.Name; + public override Symbol? ContainingSymbol => null; + public override bool IsSpecialName => true; + public override bool IsStatic => true; public override ImmutableArray GenericParameters => InterlockedUtils.InitializeDefault(ref this.genericParameters, this.BuildGenericParameters); @@ -27,12 +34,20 @@ internal sealed class SynthetizedMetadataConstructorSymbol : SynthetizedFunction public override TypeSymbol ReturnType => InterlockedUtils.InitializeNull(ref this.returnType, this.BuildReturnType); private TypeSymbol? returnType; - public override BoundStatement Body => InterlockedUtils.InitializeNull(ref this.body, this.BuildBody); - private BoundStatement? body; - private FunctionSymbol ConstructorSymbol => InterlockedUtils.InitializeNull(ref this.constructorSymbol, this.BuildConstructorSymbol); private FunctionSymbol? constructorSymbol; + public override CodegenDelegate Codegen => (codegen, target, args) => + { + var instance = target.Type; + var ctorSymbol = this.ConstructorSymbol; + if (instance.IsGenericInstance && this.IsGenericDefinition) + { + ctorSymbol = ctorSymbol.GenericInstantiate(instance, ((IGenericInstanceSymbol)instance).Context); + } + codegen.Write(NewObject(target, ctorSymbol, args)); + }; + private GenericContext? Context { get @@ -58,7 +73,7 @@ private GenericContext? Context private readonly MetadataTypeSymbol instantiatedType; private readonly MethodDefinition ctorDefinition; - public SynthetizedMetadataConstructorSymbol(MetadataTypeSymbol instantiatedType, MethodDefinition ctorDefinition) + public MetadataConstructorFunctionSymbol(MetadataTypeSymbol instantiatedType, MethodDefinition ctorDefinition) { this.instantiatedType = instantiatedType; this.ctorDefinition = ctorDefinition; @@ -78,15 +93,6 @@ private TypeSymbol BuildReturnType() => this.Context is null ? this.instantiatedType : this.instantiatedType.GenericInstantiate(this.instantiatedType.ContainingSymbol, this.Context.Value); - private BoundStatement BuildBody() => ExpressionStatement(ReturnExpression( - value: ObjectCreationExpression( - objectType: this.ReturnType, - constructor: this.ConstructorSymbol, - arguments: this.Parameters - .Select(ParameterExpression) - .Cast() - .ToImmutableArray()))); - private FunctionSymbol BuildConstructorSymbol() { var ctorSymbol = new MetadataMethodSymbol(this.ReturnType, this.ctorDefinition) as FunctionSymbol; From ef74155729ef1f4818dc70f9e80bc9ba3fa29269 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 12:01:48 +0200 Subject: [PATCH 52/55] Cleanup --- .../Symbols/Synthetized/DelegateIrFunctionSymbol.cs | 3 --- .../Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs | 1 - .../Internal/Symbols/Synthetized/IrFunctionSymbol.cs | 1 - .../Synthetized/MetadataConstructorFunctionSymbol.cs | 6 ------ 4 files changed, 11 deletions(-) diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs index ed4181538d..9d155881d1 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/DelegateIrFunctionSymbol.cs @@ -1,9 +1,6 @@ -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Draco.Compiler.Api.Syntax; namespace Draco.Compiler.Internal.Symbols.Synthetized; diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs index 52a0be4a3c..c5e3b7d04d 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/IntrinsicFunctionSymbol.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Draco.Compiler.Api.Syntax; namespace Draco.Compiler.Internal.Symbols.Synthetized; diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs index ce198d6d89..18990d55d2 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/IrFunctionSymbol.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Collections.Immutable; using Draco.Compiler.Internal.OptimizingIr; using Draco.Compiler.Internal.OptimizingIr.Model; diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataConstructorFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataConstructorFunctionSymbol.cs index a9de701c2f..c7a548f36f 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataConstructorFunctionSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataConstructorFunctionSymbol.cs @@ -1,12 +1,6 @@ -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Linq.Expressions; using System.Reflection.Metadata; -using System.Text; -using System.Threading.Tasks; -using Draco.Compiler.Internal.BoundTree; using Draco.Compiler.Internal.Symbols.Generic; using Draco.Compiler.Internal.Symbols.Metadata; using static Draco.Compiler.Internal.OptimizingIr.InstructionFactory; From 4527669e150200869c3373ed17f746a1568766c9 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 13:24:07 +0200 Subject: [PATCH 53/55] Update FunctionBodyCodegen.cs --- .../Internal/OptimizingIr/FunctionBodyCodegen.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 043c75769b..86209da055 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -13,9 +13,6 @@ namespace Draco.Compiler.Internal.OptimizingIr; -// TODO: Operators and calls became identical, can we merge them? -// During lowering we could turn operators into calls - /// /// Generates IR code on function-local level. /// From d7a1808e11ed981c19d0921b0ab8fed456927275 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 13:33:02 +0200 Subject: [PATCH 54/55] Simplification --- .../OptimizingIr/FunctionBodyCodegen.cs | 4 ---- .../Internal/OptimizingIr/Model/Procedure.cs | 18 +++--------------- .../Internal/OptimizingIr/ModuleCodegen.cs | 3 +-- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index 86209da055..c2b3944403 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -79,10 +79,6 @@ private Procedure SynthetizeProcedure(SynthetizedFunctionSymbol func) { var codegen = new FunctionBodyCodegen(this.compilation, proc); func.Body.Accept(codegen); - // TODO: Kinda duplication - // Maybe we should move parameter definition to the proc construction simply? - // Or even simpler, just project from symbol? - foreach (var param in func.Parameters) proc.DefineParameter(param); } return proc; } diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs index 0598fd279a..05bc8ebb62 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/Procedure.cs @@ -21,7 +21,7 @@ internal sealed class Procedure : IProcedure public BasicBlock Entry { get; } IBasicBlock IProcedure.Entry => this.Entry; public IReadOnlyList Generics => this.Symbol.GenericParameters; - public IReadOnlyList Parameters => this.parameters; + public IReadOnlyList Parameters => this.Symbol.Parameters; public TypeSymbol ReturnType => this.Symbol.ReturnType; public IReadOnlyDictionary BasicBlocks => this.basicBlocks; public IEnumerable BasicBlocksInDefinitionOrder => this.basicBlocks.Values @@ -30,7 +30,6 @@ internal sealed class Procedure : IProcedure public IReadOnlyList Locals => this.locals; public IReadOnlyList Registers => this.registers; - private readonly List parameters = new(); private readonly Dictionary basicBlocks = new(); private readonly List locals = new(); private readonly List registers = new(); @@ -44,22 +43,11 @@ public Procedure(Module declaringModule, FunctionSymbol symbol) public int GetParameterIndex(ParameterSymbol symbol) { - var idx = this.parameters.IndexOf(symbol); + var idx = this.Symbol.Parameters.IndexOf(symbol); if (idx == -1) throw new System.ArgumentOutOfRangeException(nameof(symbol)); return idx; } - public int DefineParameter(ParameterSymbol symbol) - { - var index = this.parameters.IndexOf(symbol); - if (index == -1) - { - index = this.parameters.Count; - this.parameters.Add(symbol); - } - return index; - } - public BasicBlock DefineBasicBlock(LabelSymbol symbol) { if (!this.basicBlocks.TryGetValue(symbol, out var block)) @@ -77,7 +65,7 @@ public int DefineLocal(LocalSymbol symbol) var index = this.locals.IndexOf(symbol); if (index == -1) { - index = this.parameters.Count; + index = this.locals.Count; this.locals.Add(symbol); } return index; diff --git a/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs index ae4e887ab9..e9b824545f 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/ModuleCodegen.cs @@ -61,9 +61,8 @@ public override void VisitFunction(FunctionSymbol functionSymbol) { if (functionSymbol is not SourceFunctionSymbol sourceFunction) return; - // Add procedure, define parameters + // Add procedure var procedure = this.module.DefineProcedure(functionSymbol); - foreach (var param in functionSymbol.Parameters) procedure.DefineParameter(param); // Create the body var body = this.RewriteBody(sourceFunction.Body); From fd9b883f924ca973205f37a83a00bc5bad05d258 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Fri, 13 Oct 2023 13:36:43 +0200 Subject: [PATCH 55/55] Update FunctionBodyCodegen.cs --- .../Internal/OptimizingIr/FunctionBodyCodegen.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs index c2b3944403..e660ebd1d6 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/FunctionBodyCodegen.cs @@ -279,6 +279,10 @@ public override IOperand VisitCallExpression(BoundCallExpression node) var irFunc = ExtractIrFunction(proc); if (irFunc is not null) { + if (receiver is not null) + { + throw new System.NotImplementedException(); + } irFunc.Codegen(this, callResult, args); } else