{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/corefx/issues/33566","repository_url":"https://api.github.com/repos/dotnet/corefx","labels_url":"https://api.github.com/repos/dotnet/corefx/issues/33566/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/33566/comments","events_url":"https://api.github.com/repos/dotnet/corefx/issues/33566/events","html_url":"https://github.com/dotnet/corefx/issues/33566","id":381884303,"node_id":"MDU6SXNzdWUzODE4ODQzMDM=","number":33566,"title":"Consider exposing a HWIntrinsic that allows efficient loading, regardless of encoding.","user":{"login":"tannergooding","id":10487869,"node_id":"MDQ6VXNlcjEwNDg3ODY5","avatar_url":"https://avatars3.githubusercontent.com/u/10487869?v=4","gravatar_id":"","url":"https://api.github.com/users/tannergooding","html_url":"https://github.com/tannergooding","followers_url":"https://api.github.com/users/tannergooding/followers","following_url":"https://api.github.com/users/tannergooding/following{/other_user}","gists_url":"https://api.github.com/users/tannergooding/gists{/gist_id}","starred_url":"https://api.github.com/users/tannergooding/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tannergooding/subscriptions","organizations_url":"https://api.github.com/users/tannergooding/orgs","repos_url":"https://api.github.com/users/tannergooding/repos","events_url":"https://api.github.com/users/tannergooding/events{/privacy}","received_events_url":"https://api.github.com/users/tannergooding/received_events","type":"User","site_admin":false},"labels":[{"id":165998434,"node_id":"MDU6TGFiZWwxNjU5OTg0MzQ=","url":"https://api.github.com/repos/dotnet/corefx/labels/api-ready-for-review","name":"api-ready-for-review","color":"5319e7","default":false},{"id":809471966,"node_id":"MDU6TGFiZWw4MDk0NzE5NjY=","url":"https://api.github.com/repos/dotnet/corefx/labels/area-System.Runtime.Intrinsics","name":"area-System.Runtime.Intrinsics","color":"d4c5f9","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/dotnet/corefx/milestones/21","html_url":"https://github.com/dotnet/corefx/milestone/21","labels_url":"https://api.github.com/repos/dotnet/corefx/milestones/21/labels","id":3242632,"node_id":"MDk6TWlsZXN0b25lMzI0MjYzMg==","number":21,"title":"3.0","description":".NET Core 3.0, next major release after 2.1. See [official release dates](https://github.com/dotnet/core/blob/master/roadmap.md) for details.\r\n\r\nWe will move important issues from Future to 3.0 as the priorities and dates for next release become more clear.","creator":{"login":"karelz","id":5776068,"node_id":"MDQ6VXNlcjU3NzYwNjg=","avatar_url":"https://avatars2.githubusercontent.com/u/5776068?v=4","gravatar_id":"","url":"https://api.github.com/users/karelz","html_url":"https://github.com/karelz","followers_url":"https://api.github.com/users/karelz/followers","following_url":"https://api.github.com/users/karelz/following{/other_user}","gists_url":"https://api.github.com/users/karelz/gists{/gist_id}","starred_url":"https://api.github.com/users/karelz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karelz/subscriptions","organizations_url":"https://api.github.com/users/karelz/orgs","repos_url":"https://api.github.com/users/karelz/repos","events_url":"https://api.github.com/users/karelz/events{/privacy}","received_events_url":"https://api.github.com/users/karelz/received_events","type":"User","site_admin":false},"open_issues":351,"closed_issues":3571,"state":"open","created_at":"2018-04-04T16:40:10Z","updated_at":"2018-11-30T19:27:29Z","due_on":"2019-03-31T07:00:00Z","closed_at":null},"comments":18,"created_at":"2018-11-17T17:45:08Z","updated_at":"2018-11-30T22:45:36Z","closed_at":null,"author_association":"MEMBER","body":"### Rationale\r\n\r\nOn x86 hardware, for SIMD instructions, there are effectively two encoding formats: \"legacy\" and \"vex\".\r\n\r\nThere are some minor differences between these two encodings, including the number of parameters they take and whether the memory operand has aligned load or unaligned load semantics.\r\n\r\nAs a brief summary:\r\n* The legacy encoding generally takes two operands (`ins reg, reg/mem`), the first serves as both a source and destination, and the last as a source which can generally be a register or memory address. The memory address form has \"aligned\" semantics and will cause an exception to be thrown if the address is not \"naturally aligned\" (generally 16-bytes).\r\n* The VEX encoding generally takes three operands (`ins reg, reg, reg/mem`), the first being the destination, the second being a source, and the last as a source which can generally be a register or memory address. The memory address form has \"unaligned\" semantics and will not cause an exception to be thrown, regardless of the input.\r\n\r\nToday, we expose both `Load` (which has unaligned semantics) and `LoadAligned` (which has aligned semantics). Given that a user will often want to generate the \"most efficient\" code possible and that the JIT, in order to preserve semantics (not silently get rid of an exception that would otherwise be thrown), changes which method it will \"fold\" depending on the encoding it is currently emitting, it may be beneficial to expose an intrinsic which allows the user to specify that \"This address is aligned, do whatever load is most efficient\". This would ensure that it can be folded regardless of the current encoding.\r\n\r\n### Proposed API\r\n\r\n```csharp\r\nnamespace System.Runtime.Intrinsics.X86\r\n{\r\n    public partial abstract class Sse\r\n    {\r\n        // Asserts `(address % 16) == 0` when optimizations are disabled\r\n        // otherwise is emitted with whatever semantics are most optimal\r\n        public Vector128<float> LoadVector128(float* address);\r\n\r\n        // Same semantics as the existing `LoadVector128`\r\n        public Vector128<float> LoadUnalignedVector128(float* address);\r\n\r\n        // No Change, shown for completeness\r\n        public Vector128<float> LoadAlignedVector128(float* address);\r\n    }\r\n\r\n    public partial abstract class Sse2\r\n    {\r\n        // Asserts `(address % 16) == 0` when optimizations are disabled\r\n        // otherwise is emitted with whatever semantics are most optimal\r\n        public Vector128<double> LoadVector128(double* address);\r\n        public Vector128<byte> LoadVector128(byte* address);\r\n        public Vector128<sbyte> LoadVector128(sbyte* address);\r\n        public Vector128<short> LoadVector128(short* address);\r\n        public Vector128<ushort> LoadVector128(ushort* address);\r\n        public Vector128<int> LoadVector128(int* address);\r\n        public Vector128<uint> LoadVector128(uint* address);\r\n        public Vector128<long> LoadVector128(long* address);\r\n        public Vector128<ulong> LoadVector128(ulong* address);\r\n\r\n        // Same semantics as the existing `LoadVector128`\r\n        public Vector128<double> LoadUnalignedVector128(double* address);\r\n        public Vector128<byte> LoadUnalignedVector128(byte* address);\r\n        public Vector128<sbyte> LoadUnalignedVector128(sbyte* address);\r\n        public Vector128<short> LoadUnalignedVector128(short* address);\r\n        public Vector128<ushort> LoadUnalignedVector128(ushort* address);\r\n        public Vector128<int> LoadUnalignedVector128(int* address);\r\n        public Vector128<uint> LoadUnalignedVector128(uint* address);\r\n        public Vector128<long> LoadUnalignedVector128(long* address);\r\n        public Vector128<ulong> LoadUnalignedVector128(ulong* address);\r\n\r\n        // No Change, shown for completeness\r\n        public Vector128<double> LoadAlignedVector128(double* address);\r\n        public Vector128<byte> LoadAlignedVector128(byte* address);\r\n        public Vector128<sbyte> LoadAlignedVector128(sbyte* address);\r\n        public Vector128<short> LoadAlignedVector128(short* address);\r\n        public Vector128<ushort> LoadAlignedVector128(ushort* address);\r\n        public Vector128<int> LoadAlignedVector128(int* address);\r\n        public Vector128<uint> LoadAlignedVector128(uint* address);\r\n        public Vector128<long> LoadAlignedVector128(long* address);\r\n        public Vector128<ulong> LoadAlignedVector128(ulong* address);\r\n    }\r\n}\r\n```\r\n\r\n### Additional Info\r\n\r\nSome open ended questions:\r\n* Is this possibly better served by analysis or hints provided to the JIT?\r\n  * Not sure if providing analysis is worthwhile, given that modern hardware (since ~2011) almost always has VEX encoding support, and this is more a nicety for if people are supporting older hardware or working around a JIT bug (`COMPlus_EnableAVX=0`)\r\n* Should we also expose `Store`, `StoreUnaligned`, and `StoreAligned` counterparts or just keep `Store` and `StoreAligned`?\r\n* Should we also expose equivalents on `Avx`/`Avx2`?\r\n  * Noting that for `Avx`/`Avx2` instructions, they require the VEX encoding and therefore always have \"unaligned\" semantics, but that Avx/Avx2 define and expose `LoadAlignedVector256`/`StoreAligned` instructions anyways\r\n* Should these instructions have a `Debug.Assert((address % 16) == 0)`?"},"comment":{"url":"https://api.github.com/repos/dotnet/corefx/issues/comments/443362604","html_url":"https://github.com/dotnet/corefx/issues/33566#issuecomment-443362604","issue_url":"https://api.github.com/repos/dotnet/corefx/issues/33566","id":443362604,"node_id":"MDEyOklzc3VlQ29tbWVudDQ0MzM2MjYwNA==","user":{"login":"fiigii","id":1263030,"node_id":"MDQ6VXNlcjEyNjMwMzA=","avatar_url":"https://avatars1.githubusercontent.com/u/1263030?v=4","gravatar_id":"","url":"https://api.github.com/users/fiigii","html_url":"https://github.com/fiigii","followers_url":"https://api.github.com/users/fiigii/followers","following_url":"https://api.github.com/users/fiigii/following{/other_user}","gists_url":"https://api.github.com/users/fiigii/gists{/gist_id}","starred_url":"https://api.github.com/users/fiigii/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fiigii/subscriptions","organizations_url":"https://api.github.com/users/fiigii/orgs","repos_url":"https://api.github.com/users/fiigii/repos","events_url":"https://api.github.com/users/fiigii/events{/privacy}","received_events_url":"https://api.github.com/users/fiigii/received_events","type":"User","site_admin":false},"created_at":"2018-11-30T22:45:36Z","updated_at":"2018-11-30T22:45:36Z","author_association":"CONTRIBUTOR","body":"> Sounds to me that you don't need some assert or other kind of check, you just need to import Load as LoadAligned. \r\n\r\nI believe the result of this proposal is just forcing most people to change `Load` to `LoadUnaligned` in their programs.\r\n\r\n> Yes, we already have cases of trying to use intrinsics and needing to write additional logic to ensure downlevel hardware would also be efficient.\r\n\r\nI want to say again `Debug.Assert((address % 16) == 0);` is useless or relying on this assert is an incorrect way to treat memory alignment. .NET Core does not have \"aligned allocateion\", so we have to deal with memory alignment in two approaches\r\n```csharp\r\nfor (;IsUnaligned(addr); addr++)\r\n{\r\n    // processing data until the memory get aligned\r\n}\r\nfor (; addr < end; addr += Vector128<int>.Count)\r\n{\r\n    var v = LoadAlignedVector128(addr); \r\n    // or LoadUnalignedVector128(addr), whatever, we recommand always using LoadUnalignedVector128\r\n    ......\r\n}\r\n```\r\nOr\r\n```csharp\r\nfor (; addr < end; addr += Vector128<int>.Count)\r\n{\r\n    var v = LoadUnalignedVector128(addr); \r\n    ......\r\n}\r\n```\r\nUsing which approach is based on profiling and it is much more important than folding loads."}}
{"actor":{"display_login":"fiigii"}}