From d63d85508da4f05c36b9dc0d99a67ae073b1bd17 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sun, 8 Oct 2023 23:18:33 +0200 Subject: [PATCH 01/24] 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 5fbac54d0..ab042438e 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 e66baa29c..1c834bf54 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 10eac09e1..90c6407b0 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 d7208e25a..907e9429c 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 1f4b59ec0..3af802640 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 ee6e12940..000000000 --- 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 930ba8014..5608f5256 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 bce0feb07..a8f6dde99 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 d29bffe84..26063eb69 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 e88a2ddbb..000000000 --- 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 c3f5beaaa..000000000 --- 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 2cf2a4bf4..b54fed0cb 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 1b0ebb502..1a6008eba 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 02/24] 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 ab042438e..06415ced9 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 03/24] 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 6f4a8ab6f..fe07e6f71 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 02938336d..97b1f941b 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 04/24] 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 06415ced9..36da2d010 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 1c834bf54..1c15b48c5 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 62e068604..329a53cae 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 37bc110ff..c8285c385 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 05/24] 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 90c6407b0..e186f899e 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 e3912f78a..ae4e887ab 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 06/24] 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 1c15b48c5..e54975fc1 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 a8f6dde99..9e263f768 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 b54fed0cb..0598fd279 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 07/24] 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 36da2d010..ca514b9e1 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 08/24] 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 f8f4cd8ec..394227883 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 ca514b9e1..be592ddab 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 e54975fc1..05b0be826 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 09/24] 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 be592ddab..891191f05 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 10/24] 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 891191f05..0974f41ef 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 05b0be826..3c82231e3 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 e186f899e..7c6792a6c 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 11/24] 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 0974f41ef..e05f12ce5 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 3c82231e3..b9ed37857 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 12/24] 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 e05f12ce5..bd38e1ef0 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 13/24] 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 b9ed37857..d0a02bbd5 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 14/24] 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 7c6792a6c..90d1d13b2 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 15/24] 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 bd38e1ef0..7c7618e06 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 7e03e1d05..0f15dddf1 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 16/24] 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 7c7618e06..ea44d553a 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 17/24] 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 1c0e0c8ca..f259bc1e1 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 9ba838701..8fd15c8bd 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 3d6509abd..827b25650 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 90d1d13b2..712445d2f 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 95aa99003..22a0072fe 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 93e50e28c..75e92131e 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 0f15dddf1..f7d53ebeb 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 ffb73d131..3014fb2e0 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 000000000..61e670046 --- /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 c69d01f3a..ba8ff96f0 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 18/24] 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 615979a3b..9a4b5de89 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 294c5775a..cac23fab5 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 c43165169..236d3028e 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 827b25650..49966e628 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 aa95b43cc..825831fd2 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 712445d2f..7467cff05 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 f7d53ebeb..51c5d54c5 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 440ddc156..02f821785 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 19/24] 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 ea44d553a..8453fc315 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 7467cff05..beaf90e55 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 907e9429c..ffcf33c6e 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 2330c5a18..000000000 --- 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 000000000..eb6d85123 --- /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 000000000..fb2b3c98f --- /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 20/24] 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 8453fc315..35eb71125 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 d0a02bbd5..c4326c094 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 21/24] 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 35eb71125..349ee081a 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 22/24] 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 349ee081a..12002b2d4 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 23/24] 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 12002b2d4..e5c6dec53 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 24/24] 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 61e670046..eb68a30d3 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. ///