Skip to content

Commit

Permalink
feat: span support (#847)
Browse files Browse the repository at this point in the history
  • Loading branch information
charsleysa committed Aug 23, 2021
1 parent 16ecea6 commit 89d2541
Show file tree
Hide file tree
Showing 35 changed files with 981 additions and 104 deletions.
4 changes: 1 addition & 3 deletions Source/Mosa.Compiler.Framework/BaseMethodCompilerStage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ protected Operand AllocateVirtualRegisterManagedPointer()
{
return AllocateVirtualRegisterI(); // temp
}

protected Operand AllocateVirtualRegisterI()
{
return Is32BitPlatform ? MethodCompiler.VirtualRegisters.Allocate(TypeSystem.BuiltIn.I4) : MethodCompiler.VirtualRegisters.Allocate(TypeSystem.BuiltIn.I8);
Expand Down Expand Up @@ -940,8 +940,6 @@ protected BaseInstruction GetLoadInstruction(MosaType type)
return IRInstruction.LoadObject;
else if (type.IsPointer)
return Select(IRInstruction.Load32, IRInstruction.Load64);
if (type.IsPointer)
return Select(IRInstruction.Load32, IRInstruction.Load64);
else if (type.IsI1)
return Select(IRInstruction.LoadSignExtend8x32, IRInstruction.LoadSignExtend8x64);
else if (type.IsI2)
Expand Down
28 changes: 24 additions & 4 deletions Source/Mosa.Compiler.Framework/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public sealed class Compiler

private Dictionary<string, IntrinsicMethodDelegate> InternalIntrinsicMethods { get; } = new Dictionary<string, IntrinsicMethodDelegate>();

private Dictionary<string, StubMethodDelegate> InternalStubMethods { get; } = new Dictionary<string, StubMethodDelegate>();

#endregion Data Members

#region Properties
Expand Down Expand Up @@ -272,14 +274,25 @@ public Compiler(MosaCompiler mosaCompiler)
foreach (var method in type.GetRuntimeMethods())
{
// Now get all the IntrinsicMethodAttribute attributes
var attributes = (IntrinsicMethodAttribute[])method.GetCustomAttributes(typeof(IntrinsicMethodAttribute), true);
var intrinsicMethodAttributes = (IntrinsicMethodAttribute[])method.GetCustomAttributes(typeof(IntrinsicMethodAttribute), true);

for (int i = 0; i < attributes.Length; i++)
for (int i = 0; i < intrinsicMethodAttributes.Length; i++)
{
var d = (IntrinsicMethodDelegate)Delegate.CreateDelegate(typeof(IntrinsicMethodDelegate), method);

// Finally add the dictionary entry mapping the target name and the delegate
InternalIntrinsicMethods.Add(attributes[i].Target, d);
InternalIntrinsicMethods.Add(intrinsicMethodAttributes[i].Target, d);
}

// Now get all the StubMethodAttribute attributes
var stubMethodAttributes = (StubMethodAttribute[])method.GetCustomAttributes(typeof(StubMethodAttribute), true);

for (int i = 0; i < stubMethodAttributes.Length; i++)
{
var d = (StubMethodDelegate)Delegate.CreateDelegate(typeof(StubMethodDelegate), method);

// Finally add the dictionary entry mapping the target name and the delegate
InternalStubMethods.Add(stubMethodAttributes[i].Target, d);
}
}
}
Expand Down Expand Up @@ -480,7 +493,7 @@ public void ExecuteCompile(int maxThreads)
{
var threadID = Thread.CurrentThread.ManagedThreadId;
int success = 0;

while (true)
{
var result = ProcessQueue(threadID);
Expand Down Expand Up @@ -547,6 +560,13 @@ public IntrinsicMethodDelegate GetInstrincMethod(string name)
return value;
}

public StubMethodDelegate GetStubMethod(string name)
{
InternalStubMethods.TryGetValue(name, out StubMethodDelegate value);

return value;
}

private void EmitCounters()
{
foreach (var counter in GlobalCounters.Export())
Expand Down
2 changes: 1 addition & 1 deletion Source/Mosa.Compiler.Framework/DelegatePatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private static BasicBlock CreateMethodStructure(MethodCompiler methodCompiler)
basicBlocks.AddHeadBlock(prologue);

// Create the epilogue block
var epiologue = basicBlocks.CreateBlock(BasicBlock.EpilogueLabel);
var epilogue = basicBlocks.CreateBlock(BasicBlock.EpilogueLabel);

var start = basicBlocks.CreateBlock(BasicBlock.StartLabel);

Expand Down
42 changes: 41 additions & 1 deletion Source/Mosa.Compiler.Framework/MethodCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ public void Compile()

InternalMethod();

StubMethod();

ExecutePipeline();

Symbol.SetReplacementStatus(MethodData.Inlined);
Expand Down Expand Up @@ -585,12 +587,50 @@ private void InternalMethod()

if (NotifyTraceLogHandler != null)
{
var traceLog = new TraceLog(TraceType.MethodInstructions, Method, "XX-External Method", MethodData.Version);
var traceLog = new TraceLog(TraceType.MethodInstructions, Method, "XX-Internal Method", MethodData.Version);
traceLog?.Log($"This method is an internal method");
NotifyTraceLogHandler.Invoke(traceLog);
}
}

private void StubMethod()
{
var intrinsicAttribute = Method.FindCustomAttribute("System.Runtime.CompilerServices.IntrinsicAttribute");

if (intrinsicAttribute == null)
return;

var methodName = $"{Method.DeclaringType.Namespace}.{Method.DeclaringType.Name}::{Method.Name}";
var stub = Compiler.GetStubMethod(methodName);

if (stub == null)
return;

IsCILStream = false;
IsExecutePipeline = true;

// Create the prologue block
var prologue = BasicBlocks.CreateBlock(BasicBlock.PrologueLabel);
BasicBlocks.AddHeadBlock(prologue);

// Create the epilogue block
var epilogue = BasicBlocks.CreateBlock(BasicBlock.EpilogueLabel);

var start = BasicBlocks.CreateBlock(BasicBlock.StartLabel);

// Add a jump instruction to the first block from the prologue
prologue.First.Insert(new InstructionNode(IRInstruction.Jmp, start));

stub(new Context(start), this);

if (NotifyTraceLogHandler != null)
{
var traceLog = new TraceLog(TraceType.MethodInstructions, Method, "XX-Stubbed Method", MethodData.Version);
traceLog?.Log($"This method is a stubbed method");
NotifyTraceLogHandler.Invoke(traceLog);
}
}

/// <summary>
/// Stops the method compiler.
/// </summary>
Expand Down
18 changes: 0 additions & 18 deletions Source/Mosa.Compiler.Framework/Stages/CILTransformationStage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2086,18 +2086,6 @@ private IntrinsicMethodDelegate ResolveIntrinsicDelegateMethod(MosaMethod method
{
intrinsic = Architecture.GetInstrinsicMethod(method.ExternMethodModule);
}
else if (method.IsInternal)
{
var methodName = $"{method.DeclaringType.FullName}::{method.Name}";

intrinsic = MethodCompiler.Compiler.GetInstrincMethod(methodName);

if (intrinsic == null)
{
// special case for plugging constructors
intrinsic = MethodCompiler.Compiler.GetInstrincMethod($"{method.DeclaringType.FullName}::{method.Name}");
}
}
else
{
var methodName = $"{method.DeclaringType.FullName}::{method.Name}";
Expand Down Expand Up @@ -2137,12 +2125,6 @@ private bool ProcessExternalCall(Context context)

return true;
}
else if (context.InvokeMethod.IsInternal)
{
intrinsic(context, MethodCompiler);

return true;
}
else
{
intrinsic(context, MethodCompiler);
Expand Down
22 changes: 22 additions & 0 deletions Source/Mosa.Compiler.Framework/StubMethodAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) MOSA Project. Licensed under the New BSD License.

using System;

namespace Mosa.Compiler.Framework
{
public delegate void StubMethodDelegate(Context context, MethodCompiler methodCompiler);

/// <summary>
/// Used for defining targets when using intrinsic replacements
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class StubMethodAttribute : Attribute
{
public string Target { get; }

public StubMethodAttribute(string target)
{
Target = target;
}
}
}
57 changes: 57 additions & 0 deletions Source/Mosa.Compiler.Framework/Stubs/ByReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) MOSA Project. Licensed under the New BSD License.

namespace Mosa.Compiler.Framework.Intrinsics
{
/// <summary>
/// IntrinsicMethods
/// </summary>
static partial class StubMethods
{
[StubMethod("System.ByReference`1::.ctor")]
public static void ByReference__ctor(Context context, MethodCompiler methodCompiler)
{
var instance = methodCompiler.Parameters[0];
var value = methodCompiler.Parameters[1];
var opInstance = methodCompiler.AllocateVirtualRegisterOrStackSlot(instance.Type);
var opValue = methodCompiler.AllocateVirtualRegisterOrStackSlot(value.Type);

// Load instance parameter
var loadInstance = BaseMethodCompilerStage.GetLoadParameterInstruction(instance.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadInstance, opInstance, instance);

// Load value parameter
var loadValue = BaseMethodCompilerStage.GetLoadParameterInstruction(value.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadValue, opValue, value);

// Store value inside instance
var store = methodCompiler.Architecture.Is32BitPlatform ? (BaseInstruction)IRInstruction.Store32 : IRInstruction.Store64;
context.AppendInstruction(store, null, opInstance, methodCompiler.ConstantZero, opValue);
context.MosaType = methodCompiler.TypeSystem.BuiltIn.I;

context.AppendInstruction(IRInstruction.Jmp, methodCompiler.BasicBlocks.EpilogueBlock);
}

[StubMethod("System.ByReference`1::get_Value")]
public static void ByReference_get_Value(Context context, MethodCompiler methodCompiler)
{
var instance = methodCompiler.Parameters[0];
var opInstance = methodCompiler.AllocateVirtualRegisterOrStackSlot(instance.Type);
var opReturn = methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType);

// Load instance parameter
var loadInstance = BaseMethodCompilerStage.GetLoadParameterInstruction(instance.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadInstance, opInstance, instance);

// Load value from instance into return operand
var loadValue = methodCompiler.Architecture.Is32BitPlatform ? (BaseInstruction)IRInstruction.Load32 : IRInstruction.Load64;
context.AppendInstruction(loadValue, opReturn, opInstance, methodCompiler.ConstantZero);
context.MosaType = methodCompiler.TypeSystem.BuiltIn.I;

// Set return
var setReturn = BaseMethodCompilerStage.GetSetReturnInstruction(opReturn.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(setReturn, null, opReturn);

context.AppendInstruction(IRInstruction.Jmp, methodCompiler.BasicBlocks.EpilogueBlock);
}
}
}
30 changes: 30 additions & 0 deletions Source/Mosa.Compiler.Framework/Stubs/RuntimeHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) MOSA Project. Licensed under the New BSD License.

namespace Mosa.Compiler.Framework.Intrinsics
{
/// <summary>
/// IntrinsicMethods
/// </summary>
static partial class StubMethods
{
[StubMethod("System.Runtime.CompilerServices.RuntimeHelpers::IsReferenceOrContainsReferences")]
public static void RuntimeHelpers_IsReferenceOrContainsReferences(Context context, MethodCompiler methodCompiler)
{
var type = methodCompiler.Method.GenericArguments[0];
var opReturn = methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType);

// FIXME: we're only checking if the current type is a reference type, we aren't checking if it contains references
var isReferenceOrContainsReferences = type.IsReferenceType;

// Move constant into return operand
var move = methodCompiler.Architecture.Is32BitPlatform ? (BaseInstruction)IRInstruction.Move32 : IRInstruction.Move64;
context.AppendInstruction(move, opReturn, methodCompiler.CreateConstant(isReferenceOrContainsReferences ? 1 : 0));

// Set return
var setReturn = BaseMethodCompilerStage.GetSetReturnInstruction(opReturn.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(setReturn, null, opReturn);

context.AppendInstruction(IRInstruction.Jmp, methodCompiler.BasicBlocks.EpilogueBlock);
}
}
}
91 changes: 85 additions & 6 deletions Source/Mosa.Compiler.Framework/Stubs/Unsafe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,95 @@ namespace Mosa.Compiler.Framework.Intrinsics
/// </summary>
static partial class StubMethods
{
[IntrinsicMethod("System.Runtime.CompilerServices.Unsafe::SizeOf")]
private static void SizeOf(Context context, MethodCompiler methodCompiler)
[StubMethod("System.Runtime.CompilerServices.Unsafe::SizeOf")]
public static void Unsafe_SizeOf(Context context, MethodCompiler methodCompiler)
{
//var size = type.IsPointer ? methodCompiler.Architecture.NativePointerSize : methodCompiler.TypeLayout.GetTypeSize(type);

var type = context.InvokeMethod.GenericArguments[0];
var type = methodCompiler.Method.GenericArguments[0];
var size = methodCompiler.TypeLayout.GetTypeSize(type);
var opReturn = methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType);

// Move constant into return operand
var move = methodCompiler.Architecture.Is32BitPlatform ? (BaseInstruction)IRInstruction.Move32 : IRInstruction.Move64;
context.AppendInstruction(move, opReturn, methodCompiler.CreateConstant(size));

// Set return
var setReturn = BaseMethodCompilerStage.GetSetReturnInstruction(opReturn.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(setReturn, null, opReturn);

context.AppendInstruction(IRInstruction.Jmp, methodCompiler.BasicBlocks.EpilogueBlock);
}

[StubMethod("System.Runtime.CompilerServices.Unsafe::AsPointer")]
[StubMethod("System.Runtime.CompilerServices.Unsafe::As")]
public static void Unsafe_As(Context context, MethodCompiler methodCompiler)
{
var source = methodCompiler.Parameters[0];
var opReturn = methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType);

// Load source into return operand
var loadSource = BaseMethodCompilerStage.GetLoadParameterInstruction(source.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadSource, opReturn, source);

// Set return
var setReturn = BaseMethodCompilerStage.GetSetReturnInstruction(opReturn.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(setReturn, null, opReturn);

context.AppendInstruction(IRInstruction.Jmp, methodCompiler.BasicBlocks.EpilogueBlock);
}

[StubMethod("System.Runtime.CompilerServices.Unsafe::AreSame")]
public static void Unsafe_AreSame(Context context, MethodCompiler methodCompiler)
{
var left = methodCompiler.Parameters[0];
var right = methodCompiler.Parameters[1];
var opLeft = methodCompiler.AllocateVirtualRegisterOrStackSlot(left.Type);
var opRight = methodCompiler.AllocateVirtualRegisterOrStackSlot(right.Type);
var opReturn = methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType);

// Load left parameter
var loadLeft = BaseMethodCompilerStage.GetLoadParameterInstruction(left.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadLeft, opLeft, left);

// Load right parameter
var loadRight = BaseMethodCompilerStage.GetLoadParameterInstruction(right.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadRight, opRight, right);

// Compare and store into result operand
context.AppendInstruction(IRInstruction.CompareObject, ConditionCode.Equal, opReturn, opLeft, opRight);

// Set return
var setReturn = BaseMethodCompilerStage.GetSetReturnInstruction(opReturn.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(setReturn, null, opReturn);

context.AppendInstruction(IRInstruction.Jmp, methodCompiler.BasicBlocks.EpilogueBlock);
}

[StubMethod("System.Runtime.CompilerServices.Unsafe::AddByteOffset")]
public static void Unsafe_AddByteOffset(Context context, MethodCompiler methodCompiler)
{
var source = methodCompiler.Parameters[0];
var byteOffset = methodCompiler.Parameters[1];
var opSource = methodCompiler.AllocateVirtualRegisterOrStackSlot(source.Type);
var opByteOffset = methodCompiler.AllocateVirtualRegisterOrStackSlot(byteOffset.Type);
var opReturn = methodCompiler.AllocateVirtualRegisterOrStackSlot(methodCompiler.Method.Signature.ReturnType);

// Load left parameter
var loadSource = BaseMethodCompilerStage.GetLoadParameterInstruction(source.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadSource, opSource, source);

// Load right parameter
var loadByteOffset = BaseMethodCompilerStage.GetLoadParameterInstruction(byteOffset.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(loadByteOffset, opByteOffset, byteOffset);

// Compare and store into result operand
var add = methodCompiler.Architecture.Is32BitPlatform ? (BaseInstruction)IRInstruction.Add32 : IRInstruction.Add64;
context.AppendInstruction(add, opReturn, opSource, opByteOffset);

// Return comparison result
var setReturn = BaseMethodCompilerStage.GetSetReturnInstruction(opReturn.Type, methodCompiler.Architecture.Is32BitPlatform);
context.AppendInstruction(setReturn, null, opReturn);

context.SetInstruction(move, context.Result, methodCompiler.CreateConstant(size));
context.AppendInstruction(IRInstruction.Jmp, methodCompiler.BasicBlocks.EpilogueBlock);
}
}
}

0 comments on commit 89d2541

Please sign in to comment.