It would be possible to substitute the field uses and get rid of both of the struct copies... but it does not look like a straightforward extension to forward sub. It might be easier with physical promotion which will have decomposed the struct copies already, but even so we would need to handle forward sub across multiple statements.
Code example from @BladeWise
We get containment in the field case, but not in the property case that ends up with IR like the above.
```csharp
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static System.Runtime.CompilerServices.MethodImplOptions;
public static class FieldsVsPropsTests
{
public static MyVec3Fields TestAdd(MyVec3Fields l, MyVec3Fields r) => MyVec3Fields.AddScalar(l, r);
public static MyVec3Props TestAdd(MyVec3Props l, MyVec3Props r) => MyVec3Props.AddScalar(l, r);
[StructLayout(LayoutKind.Sequential)]
public struct MyVec3Fields(float x, float y, float z)
{
[MethodImpl(AggressiveInlining)]
public static MyVec3Fields AddScalar(MyVec3Fields l, MyVec3Fields r) => new(l.X + r.X, l.Y + r.Y, l.Z + r.Z);
public float X = x, Y = y, Z = z;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyVec3Props(float x, float y, float z)
{
[MethodImpl(AggressiveInlining)]
public static MyVec3Props AddScalar(MyVec3Props l, MyVec3Props r) => new(l.X + r.X, l.Y + r.Y, l.Z + r.Z);
public float X
{
[MethodImpl(AggressiveInlining)] get;
[MethodImpl(AggressiveInlining)] set;
} = x;
public float Y
{
[MethodImpl(AggressiveInlining)] get;
[MethodImpl(AggressiveInlining)] set;
} = y;
public float Z
{
[MethodImpl(AggressiveInlining)] get;
[MethodImpl(AggressiveInlining)] set;
} = z;
}
}
```
For example:
It would be possible to substitute the field uses and get rid of both of the struct copies... but it does not look like a straightforward extension to forward sub. It might be easier with physical promotion which will have decomposed the struct copies already, but even so we would need to handle forward sub across multiple statements.
Code example from @BladeWise
We get containment in the field case, but not in the property case that ends up with IR like the above. ```csharp using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static System.Runtime.CompilerServices.MethodImplOptions; public static class FieldsVsPropsTests { public static MyVec3Fields TestAdd(MyVec3Fields l, MyVec3Fields r) => MyVec3Fields.AddScalar(l, r); public static MyVec3Props TestAdd(MyVec3Props l, MyVec3Props r) => MyVec3Props.AddScalar(l, r); [StructLayout(LayoutKind.Sequential)] public struct MyVec3Fields(float x, float y, float z) { [MethodImpl(AggressiveInlining)] public static MyVec3Fields AddScalar(MyVec3Fields l, MyVec3Fields r) => new(l.X + r.X, l.Y + r.Y, l.Z + r.Z); public float X = x, Y = y, Z = z; } [StructLayout(LayoutKind.Sequential)] public struct MyVec3Props(float x, float y, float z) { [MethodImpl(AggressiveInlining)] public static MyVec3Props AddScalar(MyVec3Props l, MyVec3Props r) => new(l.X + r.X, l.Y + r.Y, l.Z + r.Z); public float X { [MethodImpl(AggressiveInlining)] get; [MethodImpl(AggressiveInlining)] set; } = x; public float Y { [MethodImpl(AggressiveInlining)] get; [MethodImpl(AggressiveInlining)] set; } = y; public float Z { [MethodImpl(AggressiveInlining)] get; [MethodImpl(AggressiveInlining)] set; } = z; } } ```