Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable Int128 use in by value ABI scenarios, and fix field layout behavior #74123

Merged
merged 12 commits into from
Aug 19, 2022

Conversation

davidwrighton
Copy link
Member

@davidwrighton davidwrighton commented Aug 18, 2022

Unfortunately, attempting to actually fix all the ABI issues is probably too complex for this time in the release cycle.

  • Mark Int128 as being ABI unstable in Crossgen2. This will prevent it from appearing in function signatures
  • Adjust layout so that crossgen2 and the runtime agree about layout
    • Arm32 - Alignment of 8 bytes
    • Everywhere else - Alignment of 16 bytes
  • Disable use of Int128 in pinvokes as a by value parameter or return value. (Match behavior of Vector128<T>) (Unlike Vector128 handle scenarios such as having fields of Int128 types.)
  • Disable tests that will fail now that pinvokes are disabled
  • Build a test that will succeed now that pinvokes are disabled
  • Add test that alignment matches OS behavior
  • Add unit tests for alignment behavior
  • Update R2R version

Fixes #72206

- On Unix platforms (64 bit) use 16 byte alignment
- On Arm32 use 8 byte alignment matching the 128 byte vector type
- On other Windows platforms the 128 bit integer type isn't defined by the C compiler, but match the behavior of other 128 bit types (16 byte alignment)

Add tests to call down to native that should pass with these rules

- Disable use of Int128 as p/invoke parameter passed by value
- This disables use of these types for parameter passing in R2R images
@jkoritzinsky
Copy link
Member

If you explicitly mark Int128 as non-blittable, you can then block it in the struct marshalling stubs (and as a result block usage of any struct containing an Int128 in a P/Invoke scenario)

@@ -25,6 +32,47 @@ unsafe partial class Int128Native
[DllImport(nameof(Int128Native))]
public static extern Int128 AddInt128(Int128 lhs, Int128 rhs);


[DllImport(nameof(Int128Native))]
public static extern void AddStructWithInt128_ByRef(ref StructWithInt128 lhs, ref StructWithInt128 rhs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should pointers also be checked to make sure the marshaler doesn't change the by-ref marshalling?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done some mild testing of pointers. It should work acceptably well.

@davidwrighton
Copy link
Member Author

All failures caused by the unix arm queue getting completely overwhelmed

Comment on lines +10009 to +10011
// On Windows, no standard for Int128 has been established yet,
// although applying 16 byte alignment is consistent with treatment of 128 bit SSE types
// even on X86
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth noting that the MSVC STL does have a private __int128 that is 16-byte aligned. Clang also uses 16-byte alignment for its own Int128 when targeting the Windows ABI.

Nothing official/documented of course, but it does help justify using 16 on Windows here for managed.

Copy link
Member

@jkoritzinsky jkoritzinsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a few nits

src/coreclr/vm/classlayoutinfo.cpp Outdated Show resolved Hide resolved
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>embedded</DebugType>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The separate test? Yes, as the other test fails, and I'd like to not get rid of it. The DebugType flag, no, but it was just a copy/paste from the other project.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question was around the DebugType in particular.

Co-authored-by: Jeremy Koritzinsky <[email protected]>
Comment on lines +77 to +93
[Intrinsic]
[StructLayout(LayoutKind.Sequential)]
public readonly struct Int128
{

private readonly ulong _lower;
private readonly ulong _upper;
}

[Intrinsic]
[StructLayout(LayoutKind.Sequential)]
public readonly struct UInt128
{

private readonly ulong _lower;
private readonly ulong _upper;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[Intrinsic]
[StructLayout(LayoutKind.Sequential)]
public readonly struct Int128
{
private readonly ulong _lower;
private readonly ulong _upper;
}
[Intrinsic]
[StructLayout(LayoutKind.Sequential)]
public readonly struct UInt128
{
private readonly ulong _lower;
private readonly ulong _upper;
}
[Intrinsic]
[StructLayout(LayoutKind.Sequential)]
public readonly struct Int128
{
private readonly ulong _lower;
private readonly ulong _upper;
}
[Intrinsic]
[StructLayout(LayoutKind.Sequential)]
public readonly struct UInt128
{
private readonly ulong _lower;
private readonly ulong _upper;
}

@davidwrighton
Copy link
Member Author

The failures here are all arm64 issues hit by the arm helix queues falling over today.

@davidwrighton davidwrighton merged commit e6b5e67 into dotnet:main Aug 19, 2022
@davidwrighton
Copy link
Member Author

/backport to release/7.0-rc1

@github-actions
Copy link
Contributor

Started backporting to release/7.0-rc1: https://github.com/dotnet/runtime/actions/runs/2892554223

MichalStrehovsky added a commit to MichalStrehovsky/runtime that referenced this pull request Sep 16, 2022
dotnet#74123 broke compiling TechEmpower benchmarks with NativeAOT. We now crash with:

```
>	ILCompiler.TypeSystem.dll!Internal.TypeSystem.RuntimeDeterminedFieldLayoutAlgorithm.ComputeInstanceLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 19	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeInstanceLayout(Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 436	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.IsInt128OrHasInt128Fields.get() Line 150	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeAutoFieldLayout(Internal.TypeSystem.MetadataType type, int numInstanceFields) Line 483	C#
 	ILCompiler.Compiler.dll!ILCompiler.CompilerMetadataFieldLayoutAlgorithm.ComputeInstanceFieldLayout(Internal.TypeSystem.MetadataType type, int numInstanceFields) Line 56	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeInstanceLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 164	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeInstanceLayout(Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 436	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.InstanceFieldSize.get() Line 165	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeFieldSizeAndAlignment(Internal.TypeSystem.TypeDesc fieldType, bool hasLayout, int packingSize, out bool layoutAbiStable, out bool fieldTypeHasAutoLayout, out bool fieldTypeHasInt128Field) Line 838	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeStaticFieldLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.StaticLayoutKind layoutKind) Line 215	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeStaticFieldLayout(Internal.TypeSystem.StaticLayoutKind layoutKind) Line 473	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.GCStaticFieldSize.get() Line 302	C#
 	ILCompiler.Compiler.dll!ILCompiler.DependencyAnalysis.NativeLayoutTemplateTypeLayoutVertexNode.GetStaticDependencies(ILCompiler.DependencyAnalysis.NodeFactory context) Line 997	C#
```

https://github.com/dotnet/runtime/blob/4cf1383c8458945b7eb27ae5f57338c10ed25d54/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs#L17-L19

I was not able to come up with a standalone repro case, but this fixes compiling the benchmark. I'm not clear why native layout operates on runtime determined forms, but what I'm doing here should have equivalent behaviors, except avoiding the problem that we can no longer compute layouts of runtime determined things in some obscure scenarios due to the new code.
jkotas pushed a commit that referenced this pull request Sep 16, 2022
#74123 broke compiling TechEmpower benchmarks with NativeAOT. We now crash with:

```
>	ILCompiler.TypeSystem.dll!Internal.TypeSystem.RuntimeDeterminedFieldLayoutAlgorithm.ComputeInstanceLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 19	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeInstanceLayout(Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 436	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.IsInt128OrHasInt128Fields.get() Line 150	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeAutoFieldLayout(Internal.TypeSystem.MetadataType type, int numInstanceFields) Line 483	C#
 	ILCompiler.Compiler.dll!ILCompiler.CompilerMetadataFieldLayoutAlgorithm.ComputeInstanceFieldLayout(Internal.TypeSystem.MetadataType type, int numInstanceFields) Line 56	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeInstanceLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 164	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeInstanceLayout(Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 436	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.InstanceFieldSize.get() Line 165	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeFieldSizeAndAlignment(Internal.TypeSystem.TypeDesc fieldType, bool hasLayout, int packingSize, out bool layoutAbiStable, out bool fieldTypeHasAutoLayout, out bool fieldTypeHasInt128Field) Line 838	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeStaticFieldLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.StaticLayoutKind layoutKind) Line 215	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeStaticFieldLayout(Internal.TypeSystem.StaticLayoutKind layoutKind) Line 473	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.GCStaticFieldSize.get() Line 302	C#
 	ILCompiler.Compiler.dll!ILCompiler.DependencyAnalysis.NativeLayoutTemplateTypeLayoutVertexNode.GetStaticDependencies(ILCompiler.DependencyAnalysis.NodeFactory context) Line 997	C#
```

https://github.com/dotnet/runtime/blob/4cf1383c8458945b7eb27ae5f57338c10ed25d54/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs#L17-L19

I was not able to come up with a standalone repro case, but this fixes compiling the benchmark. I'm not clear why native layout operates on runtime determined forms, but what I'm doing here should have equivalent behaviors, except avoiding the problem that we can no longer compute layouts of runtime determined things in some obscure scenarios due to the new code.
github-actions bot pushed a commit that referenced this pull request Sep 16, 2022
#74123 broke compiling TechEmpower benchmarks with NativeAOT. We now crash with:

```
>	ILCompiler.TypeSystem.dll!Internal.TypeSystem.RuntimeDeterminedFieldLayoutAlgorithm.ComputeInstanceLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 19	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeInstanceLayout(Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 436	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.IsInt128OrHasInt128Fields.get() Line 150	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeAutoFieldLayout(Internal.TypeSystem.MetadataType type, int numInstanceFields) Line 483	C#
 	ILCompiler.Compiler.dll!ILCompiler.CompilerMetadataFieldLayoutAlgorithm.ComputeInstanceFieldLayout(Internal.TypeSystem.MetadataType type, int numInstanceFields) Line 56	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeInstanceLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 164	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeInstanceLayout(Internal.TypeSystem.InstanceLayoutKind layoutKind) Line 436	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.InstanceFieldSize.get() Line 165	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeFieldSizeAndAlignment(Internal.TypeSystem.TypeDesc fieldType, bool hasLayout, int packingSize, out bool layoutAbiStable, out bool fieldTypeHasAutoLayout, out bool fieldTypeHasInt128Field) Line 838	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.MetadataFieldLayoutAlgorithm.ComputeStaticFieldLayout(Internal.TypeSystem.DefType defType, Internal.TypeSystem.StaticLayoutKind layoutKind) Line 215	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.ComputeStaticFieldLayout(Internal.TypeSystem.StaticLayoutKind layoutKind) Line 473	C#
 	ILCompiler.TypeSystem.dll!Internal.TypeSystem.DefType.GCStaticFieldSize.get() Line 302	C#
 	ILCompiler.Compiler.dll!ILCompiler.DependencyAnalysis.NativeLayoutTemplateTypeLayoutVertexNode.GetStaticDependencies(ILCompiler.DependencyAnalysis.NodeFactory context) Line 997	C#
```

https://github.com/dotnet/runtime/blob/4cf1383c8458945b7eb27ae5f57338c10ed25d54/src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs#L17-L19

I was not able to come up with a standalone repro case, but this fixes compiling the benchmark. I'm not clear why native layout operates on runtime determined forms, but what I'm doing here should have equivalent behaviors, except avoiding the problem that we can no longer compute layouts of runtime determined things in some obscure scenarios due to the new code.
@ghost ghost locked as resolved and limited conversation to collaborators Sep 19, 2022
@davidwrighton davidwrighton deleted the fix_72206_2 branch April 13, 2023 18:53
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[U]Int128 alignment handling is in the wrong place
4 participants