diff options
| author | LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> | 2019-10-31 19:09:03 +0100 |
|---|---|---|
| committer | Ac_K <Acoustik666@gmail.com> | 2019-10-31 19:09:03 +0100 |
| commit | eee639d6ba544fa5dd9352426d55e91bc54e157d (patch) | |
| tree | 1df440ca57d8c1725e84f403fbeecddb8e508a3a /ChocolArm64/Instructions | |
| parent | 35443bac5a16ced668d84e0a22c21ca9076b3924 (diff) | |
.NET Core 3.0 is here! (#784)
* .NET Core 3.0 is here!
* Remove IMemoryManager.cs and its references.
* Add T Math/F.FusedMultiplyAdd(T, T, T). Nits.
* Nit.
* Update appveyor.yml
* Revert "Resolve Visual Studio build issues"
This reverts commit 1772128ce0fc058e6280001aace3a77a7a96897b.
* Update SvcTable.cs
Diffstat (limited to 'ChocolArm64/Instructions')
35 files changed, 0 insertions, 19195 deletions
diff --git a/ChocolArm64/Instructions/CryptoHelper.cs b/ChocolArm64/Instructions/CryptoHelper.cs deleted file mode 100644 index e9b6ed5f..00000000 --- a/ChocolArm64/Instructions/CryptoHelper.cs +++ /dev/null @@ -1,331 +0,0 @@ -// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf - -using System; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace ChocolArm64.Instructions -{ - static class CryptoHelper - { -#region "LookUp Tables" - private static readonly byte[] _sBox = new byte[] - { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 - }; - - private static readonly byte[] _invSBox = new byte[] - { - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d - }; - - private static readonly byte[] _gfMul02 = new byte[] - { - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, - 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, - 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, - 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, - 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, - 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, - 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, - 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, - 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, - 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, - 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, - 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, - 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, - 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, - 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 - }; - - private static readonly byte[] _gfMul03 = new byte[] - { - 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, - 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, - 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, - 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, - 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, - 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, - 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, - 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, - 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, - 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, - 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, - 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, - 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, - 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, - 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, - 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a - }; - - private static readonly byte[] _gfMul09 = new byte[] - { - 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, - 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, - 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, - 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, - 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, - 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, - 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, - 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, - 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, - 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, - 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, - 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, - 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, - 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, - 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, - 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 - }; - - private static readonly byte[] _gfMul0B = new byte[] - { - 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, - 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, - 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, - 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, - 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, - 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, - 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, - 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, - 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, - 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, - 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, - 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, - 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, - 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, - 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, - 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 - }; - - private static readonly byte[] _gfMul0D = new byte[] - { - 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, - 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, - 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, - 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, - 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, - 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, - 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, - 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, - 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, - 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, - 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, - 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, - 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, - 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, - 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, - 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 - }; - - private static readonly byte[] _gfMul0E = new byte[] - { - 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, - 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, - 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, - 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, - 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, - 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, - 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, - 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, - 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, - 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, - 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, - 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, - 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, - 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, - 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, - 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d - }; - - private static readonly byte[] _srPerm = new byte[] - { - 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 - }; - - private static readonly byte[] _isrPerm = new byte[] - { - 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 - }; -#endregion - - public static Vector128<float> AesInvMixColumns(Vector128<float> op) - { - byte[] inState = new byte[16]; - byte[] outState = new byte[16]; - - FromVectorToByteArray(op, inState); - - for (int columns = 0; columns <= 3; columns++) - { - int idx = columns << 2; - - byte row0 = inState[idx + 0]; // A, E, I, M: [row0, col0-col3] - byte row1 = inState[idx + 1]; // B, F, J, N: [row1, col0-col3] - byte row2 = inState[idx + 2]; // C, G, K, O: [row2, col0-col3] - byte row3 = inState[idx + 3]; // D, H, L, P: [row3, col0-col3] - - outState[idx + 0] = (byte)((uint)_gfMul0E[row0] ^ _gfMul0B[row1] ^ _gfMul0D[row2] ^ _gfMul09[row3]); - outState[idx + 1] = (byte)((uint)_gfMul09[row0] ^ _gfMul0E[row1] ^ _gfMul0B[row2] ^ _gfMul0D[row3]); - outState[idx + 2] = (byte)((uint)_gfMul0D[row0] ^ _gfMul09[row1] ^ _gfMul0E[row2] ^ _gfMul0B[row3]); - outState[idx + 3] = (byte)((uint)_gfMul0B[row0] ^ _gfMul0D[row1] ^ _gfMul09[row2] ^ _gfMul0E[row3]); - } - - FromByteArrayToVector(outState, ref op); - - return op; - } - - public static Vector128<float> AesInvShiftRows(Vector128<float> op) - { - byte[] inState = new byte[16]; - byte[] outState = new byte[16]; - - FromVectorToByteArray(op, inState); - - for (int idx = 0; idx <= 15; idx++) - { - outState[_isrPerm[idx]] = inState[idx]; - } - - FromByteArrayToVector(outState, ref op); - - return op; - } - - public static Vector128<float> AesInvSubBytes(Vector128<float> op) - { - byte[] inState = new byte[16]; - byte[] outState = new byte[16]; - - FromVectorToByteArray(op, inState); - - for (int idx = 0; idx <= 15; idx++) - { - outState[idx] = _invSBox[inState[idx]]; - } - - FromByteArrayToVector(outState, ref op); - - return op; - } - - public static Vector128<float> AesMixColumns(Vector128<float> op) - { - byte[] inState = new byte[16]; - byte[] outState = new byte[16]; - - FromVectorToByteArray(op, inState); - - for (int columns = 0; columns <= 3; columns++) - { - int idx = columns << 2; - - byte row0 = inState[idx + 0]; // A, E, I, M: [row0, col0-col3] - byte row1 = inState[idx + 1]; // B, F, J, N: [row1, col0-col3] - byte row2 = inState[idx + 2]; // C, G, K, O: [row2, col0-col3] - byte row3 = inState[idx + 3]; // D, H, L, P: [row3, col0-col3] - - outState[idx + 0] = (byte)((uint)_gfMul02[row0] ^ _gfMul03[row1] ^ row2 ^ row3); - outState[idx + 1] = (byte)((uint)row0 ^ _gfMul02[row1] ^ _gfMul03[row2] ^ row3); - outState[idx + 2] = (byte)((uint)row0 ^ row1 ^ _gfMul02[row2] ^ _gfMul03[row3]); - outState[idx + 3] = (byte)((uint)_gfMul03[row0] ^ row1 ^ row2 ^ _gfMul02[row3]); - } - - FromByteArrayToVector(outState, ref op); - - return op; - } - - public static Vector128<float> AesShiftRows(Vector128<float> op) - { - byte[] inState = new byte[16]; - byte[] outState = new byte[16]; - - FromVectorToByteArray(op, inState); - - for (int idx = 0; idx <= 15; idx++) - { - outState[_srPerm[idx]] = inState[idx]; - } - - FromByteArrayToVector(outState, ref op); - - return op; - } - - public static Vector128<float> AesSubBytes(Vector128<float> op) - { - byte[] inState = new byte[16]; - byte[] outState = new byte[16]; - - FromVectorToByteArray(op, inState); - - for (int idx = 0; idx <= 15; idx++) - { - outState[idx] = _sBox[inState[idx]]; - } - - FromByteArrayToVector(outState, ref op); - - return op; - } - - private unsafe static void FromVectorToByteArray(Vector128<float> op, byte[] state) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - fixed (byte* ptr = &state[0]) - { - Sse2.Store(ptr, Sse.StaticCast<float, byte>(op)); - } - } - - private unsafe static void FromByteArrayToVector(byte[] state, ref Vector128<float> op) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - fixed (byte* ptr = &state[0]) - { - op = Sse.StaticCast<byte, float>(Sse2.LoadVector128(ptr)); - } - } - } -} diff --git a/ChocolArm64/Instructions/Inst.cs b/ChocolArm64/Instructions/Inst.cs deleted file mode 100644 index de9ec18b..00000000 --- a/ChocolArm64/Instructions/Inst.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace ChocolArm64.Instructions -{ - struct Inst - { - public InstEmitter Emitter { get; } - public Type Type { get; } - - public static Inst Undefined => new Inst(InstEmit.Und, null); - - public Inst(InstEmitter emitter, Type type) - { - Emitter = emitter; - Type = type; - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmit32Helper.cs b/ChocolArm64/Instructions/InstEmit32Helper.cs deleted file mode 100644 index c5d08b8a..00000000 --- a/ChocolArm64/Instructions/InstEmit32Helper.cs +++ /dev/null @@ -1,146 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static class InstEmit32Helper - { - public static bool IsThumb(OpCode64 op) - { - return op is OpCodeT16; - } - - public static void EmitLoadFromRegister(ILEmitterCtx context, int register) - { - if (register == RegisterAlias.Aarch32Pc) - { - OpCode32 op = (OpCode32)context.CurrOp; - - context.EmitLdc_I4((int)op.GetPc()); - } - else - { - context.EmitLdint(GetRegisterAlias(context.Mode, register)); - } - } - - public static void EmitStoreToRegister(ILEmitterCtx context, int register) - { - if (register == RegisterAlias.Aarch32Pc) - { - context.EmitStoreContext(); - - EmitBxWritePc(context); - } - else - { - context.EmitStint(GetRegisterAlias(context.Mode, register)); - } - } - - public static void EmitBxWritePc(ILEmitterCtx context) - { - context.Emit(OpCodes.Dup); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Dup); - - context.EmitStflg((int)PState.TBit); - - ILLabel lblArmMode = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brtrue_S, lblArmMode); - - context.EmitLdc_I4(~1); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblArmMode); - - context.EmitLdc_I4(~3); - - context.MarkLabel(lblEnd); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Conv_U8); - context.Emit(OpCodes.Ret); - } - - public static int GetRegisterAlias(Aarch32Mode mode, int register) - { - //Only registers >= 8 are banked, with registers in the range [8, 12] being - //banked for the FIQ mode, and registers 13 and 14 being banked for all modes. - if ((uint)register < 8) - { - return register; - } - - return GetBankedRegisterAlias(mode, register); - } - - public static int GetBankedRegisterAlias(Aarch32Mode mode, int register) - { - switch (register) - { - case 8: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R8Fiq - : RegisterAlias.R8Usr; - - case 9: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R9Fiq - : RegisterAlias.R9Usr; - - case 10: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R10Fiq - : RegisterAlias.R10Usr; - - case 11: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R11Fiq - : RegisterAlias.R11Usr; - - case 12: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R12Fiq - : RegisterAlias.R12Usr; - - case 13: - switch (mode) - { - case Aarch32Mode.User: - case Aarch32Mode.System: return RegisterAlias.SpUsr; - case Aarch32Mode.Fiq: return RegisterAlias.SpFiq; - case Aarch32Mode.Irq: return RegisterAlias.SpIrq; - case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc; - case Aarch32Mode.Abort: return RegisterAlias.SpAbt; - case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp; - case Aarch32Mode.Undefined: return RegisterAlias.SpUnd; - - default: throw new ArgumentException(nameof(mode)); - } - - case 14: - switch (mode) - { - case Aarch32Mode.User: - case Aarch32Mode.Hypervisor: - case Aarch32Mode.System: return RegisterAlias.LrUsr; - case Aarch32Mode.Fiq: return RegisterAlias.LrFiq; - case Aarch32Mode.Irq: return RegisterAlias.LrIrq; - case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc; - case Aarch32Mode.Abort: return RegisterAlias.LrAbt; - case Aarch32Mode.Undefined: return RegisterAlias.LrUnd; - - default: throw new ArgumentException(nameof(mode)); - } - - default: throw new ArgumentOutOfRangeException(nameof(register)); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitAlu.cs b/ChocolArm64/Instructions/InstEmitAlu.cs deleted file mode 100644 index 25bd8e64..00000000 --- a/ChocolArm64/Instructions/InstEmitAlu.cs +++ /dev/null @@ -1,422 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.Intrinsics.X86; - -using static ChocolArm64.Instructions.InstEmitAluHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Adc(ILEmitterCtx context) => EmitAdc(context, false); - public static void Adcs(ILEmitterCtx context) => EmitAdc(context, true); - - private static void EmitAdc(ILEmitterCtx context, bool setFlags) - { - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Add); - - context.EmitLdflg((int)PState.CBit); - - Type[] mthdTypes = new Type[] { typeof(bool) }; - - MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes); - - context.EmitCall(mthdInfo); - - if (context.CurrOp.RegisterSize != RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.Emit(OpCodes.Add); - - if (setFlags) - { - context.EmitZnFlagCheck(); - - EmitAdcsCCheck(context); - EmitAddsVCheck(context); - } - - EmitAluStore(context); - } - - public static void Add(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Add); - - public static void Adds(ILEmitterCtx context) - { - context.TryOptMarkCondWithoutCmp(); - - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Add); - - context.EmitZnFlagCheck(); - - EmitAddsCCheck(context); - EmitAddsVCheck(context); - EmitAluStoreS(context); - } - - public static void And(ILEmitterCtx context) => EmitAluOp(context, OpCodes.And); - - public static void Ands(ILEmitterCtx context) - { - EmitAluLoadOpers(context); - - context.Emit(OpCodes.And); - - EmitZeroCvFlags(context); - - context.EmitZnFlagCheck(); - - EmitAluStoreS(context); - } - - public static void Asrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr); - - public static void Bic(ILEmitterCtx context) => EmitBic(context, false); - public static void Bics(ILEmitterCtx context) => EmitBic(context, true); - - private static void EmitBic(ILEmitterCtx context, bool setFlags) - { - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Not); - context.Emit(OpCodes.And); - - if (setFlags) - { - EmitZeroCvFlags(context); - - context.EmitZnFlagCheck(); - } - - EmitAluStore(context, setFlags); - } - - public static void Cls(ILEmitterCtx context) - { - OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - context.EmitLdc_I4(op.RegisterSize == RegisterSize.Int32 ? 32 : 64); - - SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingSigns)); - - context.EmitStintzr(op.Rd); - } - - public static void Clz(ILEmitterCtx context) - { - OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - if (Lzcnt.IsSupported) - { - Type tValue = op.RegisterSize == RegisterSize.Int32 ? typeof(uint) : typeof(ulong); - - context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { tValue })); - } - else - { - context.EmitLdc_I4(op.RegisterSize == RegisterSize.Int32 ? 32 : 64); - - SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingZeros)); - } - - context.EmitStintzr(op.Rd); - } - - public static void Eon(ILEmitterCtx context) - { - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Not); - context.Emit(OpCodes.Xor); - - EmitAluStore(context); - } - - public static void Eor(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Xor); - - public static void Extr(ILEmitterCtx context) - { - // TODO: Ensure that the Shift is valid for the Is64Bits. - OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp; - - context.EmitLdintzr(op.Rm); - - if (op.Shift > 0) - { - context.EmitLdc_I4(op.Shift); - - context.Emit(OpCodes.Shr_Un); - - context.EmitLdintzr(op.Rn); - context.EmitLdc_I4(op.GetBitsCount() - op.Shift); - - context.Emit(OpCodes.Shl); - context.Emit(OpCodes.Or); - } - - EmitAluStore(context); - } - - public static void Lslv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shl); - public static void Lsrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr_Un); - - public static void Sbc(ILEmitterCtx context) => EmitSbc(context, false); - public static void Sbcs(ILEmitterCtx context) => EmitSbc(context, true); - - private static void EmitSbc(ILEmitterCtx context, bool setFlags) - { - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Sub); - - context.EmitLdflg((int)PState.CBit); - - Type[] mthdTypes = new Type[] { typeof(bool) }; - - MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes); - - context.EmitCall(mthdInfo); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.Xor); - - if (context.CurrOp.RegisterSize != RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.Emit(OpCodes.Sub); - - if (setFlags) - { - context.EmitZnFlagCheck(); - - EmitSbcsCCheck(context); - EmitSubsVCheck(context); - } - - EmitAluStore(context); - } - - public static void Sub(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Sub); - - public static void Subs(ILEmitterCtx context) - { - context.TryOptMarkCondWithoutCmp(); - - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Sub); - - context.EmitZnFlagCheck(); - - EmitSubsCCheck(context); - EmitSubsVCheck(context); - EmitAluStoreS(context); - } - - public static void Orn(ILEmitterCtx context) - { - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Not); - context.Emit(OpCodes.Or); - - EmitAluStore(context); - } - - public static void Orr(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Or); - - public static void Rbit(ILEmitterCtx context) => EmitFallback32_64(context, - nameof(SoftFallback.ReverseBits32), - nameof(SoftFallback.ReverseBits64)); - - public static void Rev16(ILEmitterCtx context) => EmitFallback32_64(context, - nameof(SoftFallback.ReverseBytes16_32), - nameof(SoftFallback.ReverseBytes16_64)); - - public static void Rev32(ILEmitterCtx context) => EmitFallback32_64(context, - nameof(SoftFallback.ReverseBytes32_32), - nameof(SoftFallback.ReverseBytes32_64)); - - private static void EmitFallback32_64(ILEmitterCtx context, string name32, string name64) - { - OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - if (op.RegisterSize == RegisterSize.Int32) - { - SoftFallback.EmitCall(context, name32); - } - else - { - SoftFallback.EmitCall(context, name64); - } - - context.EmitStintzr(op.Rd); - } - - public static void Rev64(ILEmitterCtx context) - { - OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - SoftFallback.EmitCall(context, nameof(SoftFallback.ReverseBytes64)); - - context.EmitStintzr(op.Rd); - } - - public static void Rorv(ILEmitterCtx context) - { - EmitAluLoadRn(context); - EmitAluLoadShift(context); - - context.Emit(OpCodes.Shr_Un); - - EmitAluLoadRn(context); - - context.EmitLdc_I4(context.CurrOp.GetBitsCount()); - - EmitAluLoadShift(context); - - context.Emit(OpCodes.Sub); - context.Emit(OpCodes.Shl); - context.Emit(OpCodes.Or); - - EmitAluStore(context); - } - - public static void Sdiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div); - public static void Udiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div_Un); - - private static void EmitDiv(ILEmitterCtx context, OpCode ilOp) - { - // If Rm == 0, Rd = 0 (division by zero). - context.EmitLdc_I(0); - - EmitAluLoadRm(context); - - context.EmitLdc_I(0); - - ILLabel badDiv = new ILLabel(); - - context.Emit(OpCodes.Beq_S, badDiv); - context.Emit(OpCodes.Pop); - - if (ilOp == OpCodes.Div) - { - // If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). - long intMin = 1L << (context.CurrOp.GetBitsCount() - 1); - - context.EmitLdc_I(intMin); - - EmitAluLoadRn(context); - - context.EmitLdc_I(intMin); - - context.Emit(OpCodes.Ceq); - - EmitAluLoadRm(context); - - context.EmitLdc_I(-1); - - context.Emit(OpCodes.Ceq); - context.Emit(OpCodes.And); - context.Emit(OpCodes.Brtrue_S, badDiv); - context.Emit(OpCodes.Pop); - } - - EmitAluLoadRn(context); - EmitAluLoadRm(context); - - context.Emit(ilOp); - - context.MarkLabel(badDiv); - - EmitAluStore(context); - } - - private static void EmitAluOp(ILEmitterCtx context, OpCode ilOp) - { - EmitAluLoadOpers(context); - - context.Emit(ilOp); - - EmitAluStore(context); - } - - private static void EmitAluOpShift(ILEmitterCtx context, OpCode ilOp) - { - EmitAluLoadRn(context); - EmitAluLoadShift(context); - - context.Emit(ilOp); - - EmitAluStore(context); - } - - private static void EmitAluLoadShift(ILEmitterCtx context) - { - EmitAluLoadRm(context); - - context.EmitLdc_I(context.CurrOp.GetBitsCount() - 1); - - context.Emit(OpCodes.And); - - // Note: Only 32-bits shift values are valid, so when the value is 64-bits - // we need to cast it to a 32-bits integer. This is fine because we - // AND the value and only keep the lower 5 or 6 bits anyway -- it - // could very well fit on a byte. - if (context.CurrOp.RegisterSize != RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_I4); - } - } - - private static void EmitZeroCvFlags(ILEmitterCtx context) - { - context.EmitLdc_I4(0); - - context.EmitStflg((int)PState.VBit); - - context.EmitLdc_I4(0); - - context.EmitStflg((int)PState.CBit); - } - - public static void EmitAluStore(ILEmitterCtx context) => EmitAluStore(context, false); - public static void EmitAluStoreS(ILEmitterCtx context) => EmitAluStore(context, true); - - public static void EmitAluStore(ILEmitterCtx context, bool setFlags) - { - IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp; - - if (setFlags || op is IOpCodeAluRs64) - { - context.EmitStintzr(op.Rd); - } - else - { - context.EmitStint(op.Rd); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitAlu32.cs b/ChocolArm64/Instructions/InstEmitAlu32.cs deleted file mode 100644 index 94a8c750..00000000 --- a/ChocolArm64/Instructions/InstEmitAlu32.cs +++ /dev/null @@ -1,142 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -using static ChocolArm64.Instructions.InstEmit32Helper; -using static ChocolArm64.Instructions.InstEmitAluHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit32 - { - public static void Add(ILEmitterCtx context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - EmitAluLoadOpers(context, setCarry: false); - - context.Emit(OpCodes.Add); - - if (op.SetFlags) - { - context.EmitZnFlagCheck(); - - EmitAddsCCheck(context); - EmitAddsVCheck(context); - } - - EmitAluStore(context); - } - - public static void Cmp(ILEmitterCtx context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - EmitAluLoadOpers(context, setCarry: false); - - context.Emit(OpCodes.Sub); - - context.EmitZnFlagCheck(); - - EmitSubsCCheck(context); - EmitSubsVCheck(context); - - context.Emit(OpCodes.Pop); - } - - public static void Mov(ILEmitterCtx context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - EmitAluLoadOper2(context); - - if (op.SetFlags) - { - context.EmitZnFlagCheck(); - } - - EmitAluStore(context); - } - - public static void Sub(ILEmitterCtx context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - EmitAluLoadOpers(context, setCarry: false); - - context.Emit(OpCodes.Sub); - - if (op.SetFlags) - { - context.EmitZnFlagCheck(); - - EmitSubsCCheck(context); - EmitSubsVCheck(context); - } - - EmitAluStore(context); - } - - private static void EmitAluStore(ILEmitterCtx context) - { - IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; - - if (op.Rd == RegisterAlias.Aarch32Pc) - { - if (op.SetFlags) - { - // TODO: Load SPSR etc. - - context.EmitLdflg((int)PState.TBit); - - ILLabel lblThumb = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brtrue_S, lblThumb); - - context.EmitLdc_I4(~3); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblThumb); - - context.EmitLdc_I4(~1); - - context.MarkLabel(lblEnd); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Conv_U8); - context.Emit(OpCodes.Ret); - } - else - { - EmitAluWritePc(context); - } - } - else - { - context.EmitStint(GetRegisterAlias(context.Mode, op.Rd)); - } - } - - private static void EmitAluWritePc(ILEmitterCtx context) - { - context.EmitStoreContext(); - - if (IsThumb(context.CurrOp)) - { - context.EmitLdc_I4(~1); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Conv_U8); - context.Emit(OpCodes.Ret); - } - else - { - EmitBxWritePc(context); - } - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitAluHelper.cs b/ChocolArm64/Instructions/InstEmitAluHelper.cs deleted file mode 100644 index 64822088..00000000 --- a/ChocolArm64/Instructions/InstEmitAluHelper.cs +++ /dev/null @@ -1,462 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static class InstEmitAluHelper - { - public static void EmitAdcsCCheck(ILEmitterCtx context) - { - // C = (Rd == Rn && CIn) || Rd < Rn - context.EmitSttmp(); - context.EmitLdtmp(); - context.EmitLdtmp(); - - EmitAluLoadRn(context); - - context.Emit(OpCodes.Ceq); - - context.EmitLdflg((int)PState.CBit); - - context.Emit(OpCodes.And); - - context.EmitLdtmp(); - - EmitAluLoadRn(context); - - context.Emit(OpCodes.Clt_Un); - context.Emit(OpCodes.Or); - - context.EmitStflg((int)PState.CBit); - } - - public static void EmitAddsCCheck(ILEmitterCtx context) - { - // C = Rd < Rn - context.Emit(OpCodes.Dup); - - EmitAluLoadRn(context); - - context.Emit(OpCodes.Clt_Un); - - context.EmitStflg((int)PState.CBit); - } - - public static void EmitAddsVCheck(ILEmitterCtx context) - { - // V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0 - context.Emit(OpCodes.Dup); - - EmitAluLoadRn(context); - - context.Emit(OpCodes.Xor); - - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Xor); - context.Emit(OpCodes.Not); - context.Emit(OpCodes.And); - - context.EmitLdc_I(0); - - context.Emit(OpCodes.Clt); - - context.EmitStflg((int)PState.VBit); - } - - public static void EmitSbcsCCheck(ILEmitterCtx context) - { - // C = (Rn == Rm && CIn) || Rn > Rm - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Ceq); - - context.EmitLdflg((int)PState.CBit); - - context.Emit(OpCodes.And); - - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Cgt_Un); - context.Emit(OpCodes.Or); - - context.EmitStflg((int)PState.CBit); - } - - public static void EmitSubsCCheck(ILEmitterCtx context) - { - // C = Rn == Rm || Rn > Rm = !(Rn < Rm) - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Clt_Un); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.Xor); - - context.EmitStflg((int)PState.CBit); - } - - public static void EmitSubsVCheck(ILEmitterCtx context) - { - // V = (Rd ^ Rn) & (Rn ^ Rm) < 0 - context.Emit(OpCodes.Dup); - - EmitAluLoadRn(context); - - context.Emit(OpCodes.Xor); - - EmitAluLoadOpers(context); - - context.Emit(OpCodes.Xor); - context.Emit(OpCodes.And); - - context.EmitLdc_I(0); - - context.Emit(OpCodes.Clt); - - context.EmitStflg((int)PState.VBit); - } - - public static void EmitAluLoadRm(ILEmitterCtx context) - { - if (context.CurrOp is IOpCodeAluRs64 op) - { - context.EmitLdintzr(op.Rm); - } - else if (context.CurrOp is OpCode32AluRsImm op32) - { - InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm); - } - else - { - throw new InvalidOperationException(); - } - } - - public static void EmitAluLoadOpers(ILEmitterCtx context, bool setCarry = true) - { - EmitAluLoadRn(context); - EmitAluLoadOper2(context, setCarry); - } - - public static void EmitAluLoadRn(ILEmitterCtx context) - { - if (context.CurrOp is IOpCodeAlu64 op) - { - if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64) - { - context.EmitLdintzr(op.Rn); - } - else - { - context.EmitLdint(op.Rn); - } - } - else if (context.CurrOp is IOpCode32Alu op32) - { - InstEmit32Helper.EmitLoadFromRegister(context, op32.Rn); - } - else - { - throw new InvalidOperationException(); - } - } - - public static void EmitAluLoadOper2(ILEmitterCtx context, bool setCarry = true) - { - switch (context.CurrOp) - { - // ARM32. - case OpCode32AluImm op: - context.EmitLdc_I4(op.Imm); - - if (op.SetFlags && op.IsRotated) - { - context.EmitLdc_I4((int)((uint)op.Imm >> 31)); - - context.EmitStflg((int)PState.CBit); - } - break; - - case OpCode32AluRsImm op: - EmitLoadRmShiftedByImmediate(context, op, setCarry); - break; - - case OpCodeT16AluImm8 op: - context.EmitLdc_I4(op.Imm); - break; - - // ARM64. - case IOpCodeAluImm64 op: - context.EmitLdc_I(op.Imm); - break; - - case IOpCodeAluRs64 op: - context.EmitLdintzr(op.Rm); - - switch (op.ShiftType) - { - case ShiftType.Lsl: context.EmitLsl(op.Shift); break; - case ShiftType.Lsr: context.EmitLsr(op.Shift); break; - case ShiftType.Asr: context.EmitAsr(op.Shift); break; - case ShiftType.Ror: context.EmitRor(op.Shift); break; - } - break; - - case IOpCodeAluRx64 op: - context.EmitLdintzr(op.Rm); - context.EmitCast(op.IntType); - context.EmitLsl(op.Shift); - break; - - default: throw new InvalidOperationException(); - } - } - - public static void EmitSetNzcv(ILEmitterCtx context) - { - context.Emit(OpCodes.Dup); - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.And); - context.EmitStflg((int)PState.VBit); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr); - context.Emit(OpCodes.Dup); - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.And); - context.EmitStflg((int)PState.CBit); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr); - context.Emit(OpCodes.Dup); - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.And); - context.EmitStflg((int)PState.ZBit); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr); - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.And); - context.EmitStflg((int)PState.NBit); - } - - // ARM32 helpers. - private static void EmitLoadRmShiftedByImmediate(ILEmitterCtx context, OpCode32AluRsImm op, bool setCarry) - { - int shift = op.Imm; - - if (shift == 0) - { - switch (op.ShiftType) - { - case ShiftType.Lsr: shift = 32; break; - case ShiftType.Asr: shift = 32; break; - case ShiftType.Ror: shift = 1; break; - } - } - - context.EmitLdint(op.Rm); - - if (shift != 0) - { - setCarry &= op.SetFlags; - - switch (op.ShiftType) - { - case ShiftType.Lsl: EmitLslC(context, setCarry, shift); break; - case ShiftType.Lsr: EmitLsrC(context, setCarry, shift); break; - case ShiftType.Asr: EmitAsrC(context, setCarry, shift); break; - case ShiftType.Ror: - if (op.Imm != 0) - { - EmitRorC(context, setCarry, shift); - } - else - { - EmitRrxC(context, setCarry); - } - break; - } - } - } - - private static void EmitLslC(ILEmitterCtx context, bool setCarry, int shift) - { - if ((uint)shift > 32) - { - EmitShiftByMoreThan32(context, setCarry); - } - else if (shift == 32) - { - if (setCarry) - { - context.EmitLdc_I4(1); - - context.Emit(OpCodes.And); - - context.EmitStflg((int)PState.CBit); - } - else - { - context.Emit(OpCodes.Pop); - } - - context.EmitLdc_I4(0); - } - else - { - if (setCarry) - { - context.Emit(OpCodes.Dup); - - context.EmitLsr(32 - shift); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.And); - - context.EmitStflg((int)PState.CBit); - } - - context.EmitLsl(shift); - } - } - - private static void EmitLsrC(ILEmitterCtx context, bool setCarry, int shift) - { - if ((uint)shift > 32) - { - EmitShiftByMoreThan32(context, setCarry); - } - else if (shift == 32) - { - if (setCarry) - { - context.EmitLsr(31); - - context.EmitStflg((int)PState.CBit); - } - else - { - context.Emit(OpCodes.Pop); - } - - context.EmitLdc_I4(0); - } - else - { - context.Emit(OpCodes.Dup); - - context.EmitLsr(shift - 1); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.And); - - context.EmitStflg((int)PState.CBit); - - context.EmitLsr(shift); - } - } - - private static void EmitShiftByMoreThan32(ILEmitterCtx context, bool setCarry) - { - context.Emit(OpCodes.Pop); - - context.EmitLdc_I4(0); - - if (setCarry) - { - context.Emit(OpCodes.Dup); - - context.EmitStflg((int)PState.CBit); - } - } - - private static void EmitAsrC(ILEmitterCtx context, bool setCarry, int shift) - { - if ((uint)shift >= 32) - { - context.EmitAsr(31); - - if (setCarry) - { - context.Emit(OpCodes.Dup); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.And); - - context.EmitStflg((int)PState.CBit); - } - } - else - { - if (setCarry) - { - context.Emit(OpCodes.Dup); - - context.EmitLsr(shift - 1); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.And); - - context.EmitStflg((int)PState.CBit); - } - - context.EmitAsr(shift); - } - } - - private static void EmitRorC(ILEmitterCtx context, bool setCarry, int shift) - { - shift &= 0x1f; - - context.EmitRor(shift); - - if (setCarry) - { - context.Emit(OpCodes.Dup); - - context.EmitLsr(31); - - context.EmitStflg((int)PState.CBit); - } - } - - private static void EmitRrxC(ILEmitterCtx context, bool setCarry) - { - // Rotate right by 1 with carry. - if (setCarry) - { - context.Emit(OpCodes.Dup); - - context.EmitLdc_I4(1); - - context.Emit(OpCodes.And); - - context.EmitSttmp(); - } - - context.EmitLsr(1); - - context.EmitLdflg((int)PState.CBit); - - context.EmitLsl(31); - - context.Emit(OpCodes.Or); - - if (setCarry) - { - context.EmitLdtmp(); - context.EmitStflg((int)PState.CBit); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitBfm.cs b/ChocolArm64/Instructions/InstEmitBfm.cs deleted file mode 100644 index 75e259c1..00000000 --- a/ChocolArm64/Instructions/InstEmitBfm.cs +++ /dev/null @@ -1,243 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Bfm(ILEmitterCtx context) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - if (op.Pos < op.Shift) - { - // BFI. - context.EmitLdintzr(op.Rn); - - int shift = op.GetBitsCount() - op.Shift; - - int width = op.Pos + 1; - - long mask = (long)(ulong.MaxValue >> (64 - width)); - - context.EmitLdc_I(mask); - - context.Emit(OpCodes.And); - - context.EmitLsl(shift); - - context.EmitLdintzr(op.Rd); - - context.EmitLdc_I(~(mask << shift)); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Or); - - context.EmitStintzr(op.Rd); - } - else - { - // BFXIL. - context.EmitLdintzr(op.Rn); - - context.EmitLsr(op.Shift); - - int width = op.Pos - op.Shift + 1; - - long mask = (long)(ulong.MaxValue >> (64 - width)); - - context.EmitLdc_I(mask); - - context.Emit(OpCodes.And); - - context.EmitLdintzr(op.Rd); - - context.EmitLdc_I(~mask); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Or); - - context.EmitStintzr(op.Rd); - } - } - - public static void Sbfm(ILEmitterCtx context) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - int bitsCount = op.GetBitsCount(); - - if (op.Pos + 1 == bitsCount) - { - EmitSbfmShift(context); - } - else if (op.Pos < op.Shift) - { - EmitSbfiz(context); - } - else if (op.Pos == 7 && op.Shift == 0) - { - EmitSbfmCast(context, OpCodes.Conv_I1); - } - else if (op.Pos == 15 && op.Shift == 0) - { - EmitSbfmCast(context, OpCodes.Conv_I2); - } - else if (op.Pos == 31 && op.Shift == 0) - { - EmitSbfmCast(context, OpCodes.Conv_I4); - } - else - { - EmitBfmLoadRn(context); - - context.EmitLdintzr(op.Rn); - - context.EmitLsl(bitsCount - 1 - op.Pos); - context.EmitAsr(bitsCount - 1); - - context.EmitLdc_I(~op.TMask); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Or); - - context.EmitStintzr(op.Rd); - } - } - - public static void Ubfm(ILEmitterCtx context) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - if (op.Pos + 1 == op.GetBitsCount()) - { - EmitUbfmShift(context); - } - else if (op.Pos < op.Shift) - { - EmitUbfiz(context); - } - else if (op.Pos + 1 == op.Shift) - { - EmitBfmLsl(context); - } - else if (op.Pos == 7 && op.Shift == 0) - { - EmitUbfmCast(context, OpCodes.Conv_U1); - } - else if (op.Pos == 15 && op.Shift == 0) - { - EmitUbfmCast(context, OpCodes.Conv_U2); - } - else - { - EmitBfmLoadRn(context); - - context.EmitStintzr(op.Rd); - } - } - - private static void EmitSbfiz(ILEmitterCtx context) => EmitBfiz(context, true); - private static void EmitUbfiz(ILEmitterCtx context) => EmitBfiz(context, false); - - private static void EmitBfiz(ILEmitterCtx context, bool signed) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - int width = op.Pos + 1; - - context.EmitLdintzr(op.Rn); - - context.EmitLsl(op.GetBitsCount() - width); - - if (signed) - { - context.EmitAsr(op.Shift - width); - } - else - { - context.EmitLsr(op.Shift - width); - } - - context.EmitStintzr(op.Rd); - } - - private static void EmitSbfmCast(ILEmitterCtx context, OpCode ilOp) - { - EmitBfmCast(context, ilOp, true); - } - - private static void EmitUbfmCast(ILEmitterCtx context, OpCode ilOp) - { - EmitBfmCast(context, ilOp, false); - } - - private static void EmitBfmCast(ILEmitterCtx context, OpCode ilOp, bool signed) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - context.Emit(ilOp); - - if (op.RegisterSize != RegisterSize.Int32) - { - context.Emit(signed - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8); - } - - context.EmitStintzr(op.Rd); - } - - private static void EmitSbfmShift(ILEmitterCtx context) - { - EmitBfmShift(context, true); - } - - private static void EmitUbfmShift(ILEmitterCtx context) - { - EmitBfmShift(context, false); - } - - private static void EmitBfmShift(ILEmitterCtx context, bool signed) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - context.EmitLdc_I4(op.Shift); - - context.Emit(signed - ? OpCodes.Shr - : OpCodes.Shr_Un); - - context.EmitStintzr(op.Rd); - } - - private static void EmitBfmLsl(ILEmitterCtx context) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - context.EmitLsl(op.GetBitsCount() - op.Shift); - - context.EmitStintzr(op.Rd); - } - - private static void EmitBfmLoadRn(ILEmitterCtx context) - { - OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - context.EmitRor(op.Shift); - - context.EmitLdc_I(op.WMask & op.TMask); - - context.Emit(OpCodes.And); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitCcmp.cs b/ChocolArm64/Instructions/InstEmitCcmp.cs deleted file mode 100644 index e21dc696..00000000 --- a/ChocolArm64/Instructions/InstEmitCcmp.cs +++ /dev/null @@ -1,82 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instructions.InstEmitAluHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - private enum CcmpOp - { - Cmp, - Cmn - } - - public static void Ccmn(ILEmitterCtx context) => EmitCcmp(context, CcmpOp.Cmn); - public static void Ccmp(ILEmitterCtx context) => EmitCcmp(context, CcmpOp.Cmp); - - private static void EmitCcmp(ILEmitterCtx context, CcmpOp cmpOp) - { - OpCodeCcmp64 op = (OpCodeCcmp64)context.CurrOp; - - ILLabel lblTrue = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitCondBranch(lblTrue, op.Cond); - - context.EmitLdc_I4((op.Nzcv >> 0) & 1); - - context.EmitStflg((int)PState.VBit); - - context.EmitLdc_I4((op.Nzcv >> 1) & 1); - - context.EmitStflg((int)PState.CBit); - - context.EmitLdc_I4((op.Nzcv >> 2) & 1); - - context.EmitStflg((int)PState.ZBit); - - context.EmitLdc_I4((op.Nzcv >> 3) & 1); - - context.EmitStflg((int)PState.NBit); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblTrue); - - EmitAluLoadOpers(context); - - if (cmpOp == CcmpOp.Cmp) - { - context.Emit(OpCodes.Sub); - - context.EmitZnFlagCheck(); - - EmitSubsCCheck(context); - EmitSubsVCheck(context); - } - else if (cmpOp == CcmpOp.Cmn) - { - context.Emit(OpCodes.Add); - - context.EmitZnFlagCheck(); - - EmitAddsCCheck(context); - EmitAddsVCheck(context); - } - else - { - throw new ArgumentException(nameof(cmpOp)); - } - - context.Emit(OpCodes.Pop); - - context.MarkLabel(lblEnd); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitCsel.cs b/ChocolArm64/Instructions/InstEmitCsel.cs deleted file mode 100644 index 7008a8c7..00000000 --- a/ChocolArm64/Instructions/InstEmitCsel.cs +++ /dev/null @@ -1,59 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - private enum CselOperation - { - None, - Increment, - Invert, - Negate - } - - public static void Csel(ILEmitterCtx context) => EmitCsel(context, CselOperation.None); - public static void Csinc(ILEmitterCtx context) => EmitCsel(context, CselOperation.Increment); - public static void Csinv(ILEmitterCtx context) => EmitCsel(context, CselOperation.Invert); - public static void Csneg(ILEmitterCtx context) => EmitCsel(context, CselOperation.Negate); - - private static void EmitCsel(ILEmitterCtx context, CselOperation cselOp) - { - OpCodeCsel64 op = (OpCodeCsel64)context.CurrOp; - - ILLabel lblTrue = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitCondBranch(lblTrue, op.Cond); - context.EmitLdintzr(op.Rm); - - if (cselOp == CselOperation.Increment) - { - context.EmitLdc_I(1); - - context.Emit(OpCodes.Add); - } - else if (cselOp == CselOperation.Invert) - { - context.Emit(OpCodes.Not); - } - else if (cselOp == CselOperation.Negate) - { - context.Emit(OpCodes.Neg); - } - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblTrue); - - context.EmitLdintzr(op.Rn); - - context.MarkLabel(lblEnd); - - context.EmitStintzr(op.Rd); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitException.cs b/ChocolArm64/Instructions/InstEmitException.cs deleted file mode 100644 index c835fb0d..00000000 --- a/ChocolArm64/Instructions/InstEmitException.cs +++ /dev/null @@ -1,87 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Brk(ILEmitterCtx context) - { - EmitExceptionCall(context, nameof(CpuThreadState.OnBreak)); - } - - public static void Svc(ILEmitterCtx context) - { - EmitExceptionCall(context, nameof(CpuThreadState.OnSvcCall)); - } - - private static void EmitExceptionCall(ILEmitterCtx context, string mthdName) - { - OpCodeException64 op = (OpCodeException64)context.CurrOp; - - context.EmitStoreContext(); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitLdc_I8(op.Position); - context.EmitLdc_I4(op.Id); - - context.EmitPrivateCall(typeof(CpuThreadState), mthdName); - - // Check if the thread should still be running, if it isn't then we return 0 - // to force a return to the dispatcher and then exit the thread. - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCallPropGet(typeof(CpuThreadState), nameof(CpuThreadState.Running)); - - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brtrue_S, lblEnd); - - context.EmitLdc_I8(0); - - context.Emit(OpCodes.Ret); - - context.MarkLabel(lblEnd); - - if (context.CurrBlock.Next != null) - { - context.EmitLoadContext(); - } - else - { - context.EmitLdc_I8(op.Position + 4); - - context.Emit(OpCodes.Ret); - } - } - - public static void Und(ILEmitterCtx context) - { - OpCode64 op = context.CurrOp; - - context.EmitStoreContext(); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitLdc_I8(op.Position); - context.EmitLdc_I4(op.RawOpCode); - - context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.OnUndefined)); - - if (context.CurrBlock.Next != null) - { - context.EmitLoadContext(); - } - else - { - context.EmitLdc_I8(op.Position + 4); - - context.Emit(OpCodes.Ret); - } - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitFlow.cs b/ChocolArm64/Instructions/InstEmitFlow.cs deleted file mode 100644 index 6355b8b4..00000000 --- a/ChocolArm64/Instructions/InstEmitFlow.cs +++ /dev/null @@ -1,181 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -using static ChocolArm64.Instructions.InstEmitFlowHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void B(ILEmitterCtx context) - { - OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp; - - if (context.CurrBlock.Branch != null) - { - context.Emit(OpCodes.Br, context.GetLabel(op.Imm)); - } - else - { - context.EmitStoreContext(); - context.EmitLdc_I8(op.Imm); - - context.Emit(OpCodes.Ret); - } - } - - public static void B_Cond(ILEmitterCtx context) - { - OpCodeBImmCond64 op = (OpCodeBImmCond64)context.CurrOp; - - EmitBranch(context, op.Cond); - } - - public static void Bl(ILEmitterCtx context) - { - OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp; - - context.EmitLdc_I(op.Position + 4); - context.EmitStint(RegisterAlias.Lr); - - EmitCall(context, op.Imm); - } - - public static void Blr(ILEmitterCtx context) - { - OpCodeBReg64 op = (OpCodeBReg64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - context.EmitLdc_I(op.Position + 4); - context.EmitStint(RegisterAlias.Lr); - context.EmitStoreContext(); - - EmitVirtualCall(context); - } - - public static void Br(ILEmitterCtx context) - { - OpCodeBReg64 op = (OpCodeBReg64)context.CurrOp; - - context.HasIndirectJump = true; - - context.EmitStoreContext(); - context.EmitLdintzr(op.Rn); - - EmitVirtualJump(context); - } - - public static void Cbnz(ILEmitterCtx context) => EmitCb(context, OpCodes.Bne_Un); - public static void Cbz(ILEmitterCtx context) => EmitCb(context, OpCodes.Beq); - - private static void EmitCb(ILEmitterCtx context, OpCode ilOp) - { - OpCodeBImmCmp64 op = (OpCodeBImmCmp64)context.CurrOp; - - context.EmitLdintzr(op.Rt); - context.EmitLdc_I(0); - - EmitBranch(context, ilOp); - } - - public static void Ret(ILEmitterCtx context) - { - context.EmitStoreContext(); - context.EmitLdint(RegisterAlias.Lr); - - context.Emit(OpCodes.Ret); - } - - public static void Tbnz(ILEmitterCtx context) => EmitTb(context, OpCodes.Bne_Un); - public static void Tbz(ILEmitterCtx context) => EmitTb(context, OpCodes.Beq); - - private static void EmitTb(ILEmitterCtx context, OpCode ilOp) - { - OpCodeBImmTest64 op = (OpCodeBImmTest64)context.CurrOp; - - context.EmitLdintzr(op.Rt); - context.EmitLdc_I(1L << op.Pos); - - context.Emit(OpCodes.And); - - context.EmitLdc_I(0); - - EmitBranch(context, ilOp); - } - - private static void EmitBranch(ILEmitterCtx context, Condition cond) - { - OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp; - - if (context.CurrBlock.Branch != null) - { - context.EmitCondBranch(context.GetLabel(op.Imm), cond); - - if (context.CurrBlock.Next == null) - { - context.EmitStoreContext(); - context.EmitLdc_I8(op.Position + 4); - - context.Emit(OpCodes.Ret); - } - } - else - { - context.EmitStoreContext(); - - ILLabel lblTaken = new ILLabel(); - - context.EmitCondBranch(lblTaken, cond); - - context.EmitLdc_I8(op.Position + 4); - - context.Emit(OpCodes.Ret); - - context.MarkLabel(lblTaken); - - context.EmitLdc_I8(op.Imm); - - context.Emit(OpCodes.Ret); - } - } - - private static void EmitBranch(ILEmitterCtx context, OpCode ilOp) - { - OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp; - - if (context.CurrBlock.Branch != null) - { - context.Emit(ilOp, context.GetLabel(op.Imm)); - - if (context.CurrBlock.Next == null) - { - context.EmitStoreContext(); - context.EmitLdc_I8(op.Position + 4); - - context.Emit(OpCodes.Ret); - } - } - else - { - context.EmitStoreContext(); - - ILLabel lblTaken = new ILLabel(); - - context.Emit(ilOp, lblTaken); - - context.EmitLdc_I8(op.Position + 4); - - context.Emit(OpCodes.Ret); - - context.MarkLabel(lblTaken); - - context.EmitLdc_I8(op.Imm); - - context.Emit(OpCodes.Ret); - } - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitFlow32.cs b/ChocolArm64/Instructions/InstEmitFlow32.cs deleted file mode 100644 index 133e2784..00000000 --- a/ChocolArm64/Instructions/InstEmitFlow32.cs +++ /dev/null @@ -1,81 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -using static ChocolArm64.Instructions.InstEmit32Helper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit32 - { - public static void B(ILEmitterCtx context) - { - IOpCode32BImm op = (IOpCode32BImm)context.CurrOp; - - if (context.CurrBlock.Branch != null) - { - context.Emit(OpCodes.Br, context.GetLabel(op.Imm)); - } - else - { - context.EmitStoreContext(); - context.EmitLdc_I8(op.Imm); - - context.Emit(OpCodes.Ret); - } - } - - public static void Bl(ILEmitterCtx context) - { - Blx(context, x: false); - } - - public static void Blx(ILEmitterCtx context) - { - Blx(context, x: true); - } - - public static void Bx(ILEmitterCtx context) - { - IOpCode32BReg op = (IOpCode32BReg)context.CurrOp; - - context.EmitStoreContext(); - - EmitLoadFromRegister(context, op.Rm); - - EmitBxWritePc(context); - } - - private static void Blx(ILEmitterCtx context, bool x) - { - IOpCode32BImm op = (IOpCode32BImm)context.CurrOp; - - uint pc = op.GetPc(); - - bool isThumb = IsThumb(context.CurrOp); - - if (!isThumb) - { - context.EmitLdc_I(op.GetPc() - 4); - } - else - { - context.EmitLdc_I(op.GetPc() | 1); - } - - context.EmitStint(GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr)); - - // If x is true, then this is a branch with link and exchange. - // In this case we need to swap the mode between Arm <-> Thumb. - if (x) - { - context.EmitLdc_I4(isThumb ? 0 : 1); - - context.EmitStflg((int)PState.TBit); - } - - InstEmitFlowHelper.EmitCall(context, op.Imm); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitFlowHelper.cs b/ChocolArm64/Instructions/InstEmitFlowHelper.cs deleted file mode 100644 index f36fe5a1..00000000 --- a/ChocolArm64/Instructions/InstEmitFlowHelper.cs +++ /dev/null @@ -1,144 +0,0 @@ -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static class InstEmitFlowHelper - { - public static void EmitCall(ILEmitterCtx context, long imm) - { - if (context.Tier == TranslationTier.Tier0) - { - context.EmitStoreContext(); - - context.TranslateAhead(imm); - - context.EmitLdc_I8(imm); - - context.Emit(OpCodes.Ret); - - return; - } - - if (!context.TryOptEmitSubroutineCall()) - { - context.HasSlowCall = true; - - context.EmitStoreContext(); - - context.TranslateAhead(imm); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitLdfld(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator), - BindingFlags.Instance | - BindingFlags.NonPublic)); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdc_I8(imm); - context.EmitLdc_I4((int)CallType.Call); - - context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine)); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - - context.EmitCall(typeof(TranslatedSub), nameof(TranslatedSub.Execute)); - } - - EmitContinueOrReturnCheck(context); - } - - public static void EmitVirtualCall(ILEmitterCtx context) - { - EmitVirtualCallOrJump(context, isJump: false); - } - - public static void EmitVirtualJump(ILEmitterCtx context) - { - EmitVirtualCallOrJump(context, isJump: true); - } - - private static void EmitVirtualCallOrJump(ILEmitterCtx context, bool isJump) - { - if (context.Tier == TranslationTier.Tier0) - { - context.Emit(OpCodes.Ret); - } - else - { - context.EmitSttmp(); - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitLdfld(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator), - BindingFlags.Instance | - BindingFlags.NonPublic)); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdtmp(); - context.EmitLdc_I4(isJump - ? (int)CallType.VirtualJump - : (int)CallType.VirtualCall); - - context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine)); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - - if (isJump) - { - // The tail prefix allows the JIT to jump to the next function, - // while releasing the stack space used by the current one. - // This is ideal for BR ARM instructions, which are - // basically indirect tail calls. - context.Emit(OpCodes.Tailcall); - } - - MethodInfo mthdInfo = typeof(ArmSubroutine).GetMethod("Invoke"); - - context.EmitCall(mthdInfo, isVirtual: true); - - if (!isJump) - { - EmitContinueOrReturnCheck(context); - } - else - { - context.Emit(OpCodes.Ret); - } - } - } - - private static void EmitContinueOrReturnCheck(ILEmitterCtx context) - { - // Note: The return value of the called method will be placed - // at the Stack, the return value is always a Int64 with the - // return address of the function. We check if the address is - // correct, if it isn't we keep returning until we reach the dispatcher. - if (context.CurrBlock.Next != null) - { - context.Emit(OpCodes.Dup); - - context.EmitLdc_I8(context.CurrOp.Position + 4); - - ILLabel lblContinue = new ILLabel(); - - context.Emit(OpCodes.Beq_S, lblContinue); - context.Emit(OpCodes.Ret); - - context.MarkLabel(lblContinue); - - context.Emit(OpCodes.Pop); - - context.EmitLoadContext(); - } - else - { - context.Emit(OpCodes.Ret); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitHash.cs b/ChocolArm64/Instructions/InstEmitHash.cs deleted file mode 100644 index 7e21a886..00000000 --- a/ChocolArm64/Instructions/InstEmitHash.cs +++ /dev/null @@ -1,115 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Runtime.Intrinsics.X86; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Crc32b(ILEmitterCtx context) - { - EmitCrc32(context, nameof(SoftFallback.Crc32B)); - } - - public static void Crc32h(ILEmitterCtx context) - { - EmitCrc32(context, nameof(SoftFallback.Crc32H)); - } - - public static void Crc32w(ILEmitterCtx context) - { - EmitCrc32(context, nameof(SoftFallback.Crc32W)); - } - - public static void Crc32x(ILEmitterCtx context) - { - EmitCrc32(context, nameof(SoftFallback.Crc32X)); - } - - public static void Crc32cb(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - EmitSse42Crc32(context, typeof(uint), typeof(byte)); - } - else - { - EmitCrc32(context, nameof(SoftFallback.Crc32Cb)); - } - } - - public static void Crc32ch(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - EmitSse42Crc32(context, typeof(uint), typeof(ushort)); - } - else - { - EmitCrc32(context, nameof(SoftFallback.Crc32Ch)); - } - } - - public static void Crc32cw(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - EmitSse42Crc32(context, typeof(uint), typeof(uint)); - } - else - { - EmitCrc32(context, nameof(SoftFallback.Crc32Cw)); - } - } - - public static void Crc32cx(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - EmitSse42Crc32(context, typeof(ulong), typeof(ulong)); - } - else - { - EmitCrc32(context, nameof(SoftFallback.Crc32Cx)); - } - } - - private static void EmitSse42Crc32(ILEmitterCtx context, Type tCrc, Type tData) - { - OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - context.EmitLdintzr(op.Rm); - - context.EmitCall(typeof(Sse42).GetMethod(nameof(Sse42.Crc32), new Type[] { tCrc, tData })); - - context.EmitStintzr(op.Rd); - } - - private static void EmitCrc32(ILEmitterCtx context, string name) - { - OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - if (op.RegisterSize != RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U4); - } - - context.EmitLdintzr(op.Rm); - - SoftFallback.EmitCall(context, name); - - if (op.RegisterSize != RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitStintzr(op.Rd); - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitMemory.cs b/ChocolArm64/Instructions/InstEmitMemory.cs deleted file mode 100644 index 1328f393..00000000 --- a/ChocolArm64/Instructions/InstEmitMemory.cs +++ /dev/null @@ -1,241 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -using static ChocolArm64.Instructions.InstEmitMemoryHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Adr(ILEmitterCtx context) - { - OpCodeAdr64 op = (OpCodeAdr64)context.CurrOp; - - context.EmitLdc_I(op.Position + op.Imm); - context.EmitStintzr(op.Rd); - } - - public static void Adrp(ILEmitterCtx context) - { - OpCodeAdr64 op = (OpCodeAdr64)context.CurrOp; - - context.EmitLdc_I((op.Position & ~0xfffL) + (op.Imm << 12)); - context.EmitStintzr(op.Rd); - } - - public static void Ldr(ILEmitterCtx context) => EmitLdr(context, false); - public static void Ldrs(ILEmitterCtx context) => EmitLdr(context, true); - - private static void EmitLdr(ILEmitterCtx context, bool signed) - { - OpCodeMem64 op = (OpCodeMem64)context.CurrOp; - - EmitLoadAddress(context); - - if (signed && op.Extend64) - { - EmitReadSx64Call(context, op.Size); - } - else if (signed) - { - EmitReadSx32Call(context, op.Size); - } - else - { - EmitReadZxCall(context, op.Size); - } - - if (op is IOpCodeSimd64) - { - context.EmitStvec(op.Rt); - } - else - { - context.EmitStintzr(op.Rt); - } - - EmitWBackIfNeeded(context); - } - - public static void Ldr_Literal(ILEmitterCtx context) - { - IOpCodeLit64 op = (IOpCodeLit64)context.CurrOp; - - if (op.Prefetch) - { - return; - } - - context.EmitLdc_I8(op.Imm); - - if (op.Signed) - { - EmitReadSx64Call(context, op.Size); - } - else - { - EmitReadZxCall(context, op.Size); - } - - if (op is IOpCodeSimd64) - { - context.EmitStvec(op.Rt); - } - else - { - context.EmitStint(op.Rt); - } - } - - public static void Ldp(ILEmitterCtx context) - { - OpCodeMemPair64 op = (OpCodeMemPair64)context.CurrOp; - - void EmitReadAndStore(int rt) - { - if (op.Extend64) - { - EmitReadSx64Call(context, op.Size); - } - else - { - EmitReadZxCall(context, op.Size); - } - - if (op is IOpCodeSimd64) - { - context.EmitStvec(rt); - } - else - { - context.EmitStintzr(rt); - } - } - - EmitLoadAddress(context); - - EmitReadAndStore(op.Rt); - - context.EmitLdtmp(); - context.EmitLdc_I8(1 << op.Size); - - context.Emit(OpCodes.Add); - - EmitReadAndStore(op.Rt2); - - EmitWBackIfNeeded(context); - } - - public static void Str(ILEmitterCtx context) - { - OpCodeMem64 op = (OpCodeMem64)context.CurrOp; - - EmitLoadAddress(context); - - if (op is IOpCodeSimd64) - { - context.EmitLdvec(op.Rt); - } - else - { - context.EmitLdintzr(op.Rt); - } - - EmitWriteCall(context, op.Size); - - EmitWBackIfNeeded(context); - } - - public static void Stp(ILEmitterCtx context) - { - OpCodeMemPair64 op = (OpCodeMemPair64)context.CurrOp; - - EmitLoadAddress(context); - - if (op is IOpCodeSimd64) - { - context.EmitLdvec(op.Rt); - } - else - { - context.EmitLdintzr(op.Rt); - } - - EmitWriteCall(context, op.Size); - - context.EmitLdtmp(); - context.EmitLdc_I8(1 << op.Size); - - context.Emit(OpCodes.Add); - - if (op is IOpCodeSimd64) - { - context.EmitLdvec(op.Rt2); - } - else - { - context.EmitLdintzr(op.Rt2); - } - - EmitWriteCall(context, op.Size); - - EmitWBackIfNeeded(context); - } - - private static void EmitLoadAddress(ILEmitterCtx context) - { - switch (context.CurrOp) - { - case OpCodeMemImm64 op: - context.EmitLdint(op.Rn); - - if (!op.PostIdx) - { - // Pre-indexing. - context.EmitLdc_I(op.Imm); - - context.Emit(OpCodes.Add); - } - break; - - case OpCodeMemReg64 op: - context.EmitLdint(op.Rn); - context.EmitLdintzr(op.Rm); - context.EmitCast(op.IntType); - - if (op.Shift) - { - context.EmitLsl(op.Size); - } - - context.Emit(OpCodes.Add); - break; - } - - // Save address to Scratch var since the register value may change. - context.Emit(OpCodes.Dup); - - context.EmitSttmp(); - } - - private static void EmitWBackIfNeeded(ILEmitterCtx context) - { - // Check whenever the current OpCode has post-indexed write back, if so write it. - // Note: AOpCodeMemPair inherits from AOpCodeMemImm, so this works for both. - if (context.CurrOp is OpCodeMemImm64 op && op.WBack) - { - context.EmitLdtmp(); - - if (op.PostIdx) - { - context.EmitLdc_I(op.Imm); - - context.Emit(OpCodes.Add); - } - - context.EmitStint(op.Rn); - } - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitMemory32.cs b/ChocolArm64/Instructions/InstEmitMemory32.cs deleted file mode 100644 index 807a65fe..00000000 --- a/ChocolArm64/Instructions/InstEmitMemory32.cs +++ /dev/null @@ -1,320 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instructions.InstEmit32Helper; -using static ChocolArm64.Instructions.InstEmitMemoryHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit32 - { - private const int ByteSizeLog2 = 0; - private const int HWordSizeLog2 = 1; - private const int WordSizeLog2 = 2; - private const int DWordSizeLog2 = 3; - - [Flags] - enum AccessType - { - Store = 0, - Signed = 1, - Load = 2, - - LoadZx = Load, - LoadSx = Load | Signed, - } - - public static void Ldm(ILEmitterCtx context) - { - OpCode32MemMult op = (OpCode32MemMult)context.CurrOp; - - EmitLoadFromRegister(context, op.Rn); - - bool writesToPc = (op.RegisterMask & (1 << RegisterAlias.Aarch32Pc)) != 0; - - bool writeBack = op.PostOffset != 0 && (op.Rn != RegisterAlias.Aarch32Pc || !writesToPc); - - if (writeBack) - { - context.Emit(OpCodes.Dup); - } - - context.EmitLdc_I4(op.Offset); - - context.Emit(OpCodes.Add); - - context.EmitSttmp(); - - if (writeBack) - { - context.EmitLdc_I4(op.PostOffset); - - context.Emit(OpCodes.Add); - - EmitStoreToRegister(context, op.Rn); - } - - int mask = op.RegisterMask; - int offset = 0; - - for (int register = 0; mask != 0; mask >>= 1, register++) - { - if ((mask & 1) != 0) - { - context.EmitLdtmp(); - context.EmitLdc_I4(offset); - - context.Emit(OpCodes.Add); - - EmitReadZxCall(context, WordSizeLog2); - - EmitStoreToRegister(context, register); - - offset += 4; - } - } - } - - public static void Ldr(ILEmitterCtx context) - { - EmitLoadOrStore(context, WordSizeLog2, AccessType.LoadZx); - } - - public static void Ldrb(ILEmitterCtx context) - { - EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx); - } - - public static void Ldrd(ILEmitterCtx context) - { - EmitLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx); - } - - public static void Ldrh(ILEmitterCtx context) - { - EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx); - } - - public static void Ldrsb(ILEmitterCtx context) - { - EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadSx); - } - - public static void Ldrsh(ILEmitterCtx context) - { - EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadSx); - } - - public static void Stm(ILEmitterCtx context) - { - OpCode32MemMult op = (OpCode32MemMult)context.CurrOp; - - EmitLoadFromRegister(context, op.Rn); - - context.EmitLdc_I4(op.Offset); - - context.Emit(OpCodes.Add); - - context.EmitSttmp(); - - int mask = op.RegisterMask; - int offset = 0; - - for (int register = 0; mask != 0; mask >>= 1, register++) - { - if ((mask & 1) != 0) - { - context.EmitLdtmp(); - context.EmitLdc_I4(offset); - - context.Emit(OpCodes.Add); - - EmitLoadFromRegister(context, register); - - EmitWriteCall(context, WordSizeLog2); - - // Note: If Rn is also specified on the register list, - // and Rn is the first register on this list, then the - // value that is written to memory is the unmodified value, - // before the write back. If it is on the list, but it's - // not the first one, then the value written to memory - // varies between CPUs. - if (offset == 0 && op.PostOffset != 0) - { - // Emit write back after the first write. - EmitLoadFromRegister(context, op.Rn); - - context.EmitLdc_I4(op.PostOffset); - - context.Emit(OpCodes.Add); - - EmitStoreToRegister(context, op.Rn); - } - - offset += 4; - } - } - } - - public static void Str(ILEmitterCtx context) - { - EmitLoadOrStore(context, WordSizeLog2, AccessType.Store); - } - - public static void Strb(ILEmitterCtx context) - { - EmitLoadOrStore(context, ByteSizeLog2, AccessType.Store); - } - - public static void Strd(ILEmitterCtx context) - { - EmitLoadOrStore(context, DWordSizeLog2, AccessType.Store); - } - - public static void Strh(ILEmitterCtx context) - { - EmitLoadOrStore(context, HWordSizeLog2, AccessType.Store); - } - - private static void EmitLoadOrStore(ILEmitterCtx context, int size, AccessType accType) - { - OpCode32Mem op = (OpCode32Mem)context.CurrOp; - - if (op.Index || op.WBack) - { - EmitLoadFromRegister(context, op.Rn); - - context.EmitLdc_I4(op.Imm); - - context.Emit(op.Add ? OpCodes.Add : OpCodes.Sub); - - context.EmitSttmp(); - } - - if (op.Index) - { - context.EmitLdtmp(); - } - else - { - EmitLoadFromRegister(context, op.Rn); - } - - if ((accType & AccessType.Load) != 0) - { - if ((accType & AccessType.Signed) != 0) - { - EmitReadSx32Call(context, size); - } - else - { - EmitReadZxCall(context, size); - } - - if (op.WBack) - { - context.EmitLdtmp(); - - EmitStoreToRegister(context, op.Rn); - } - - if (size == DWordSizeLog2) - { - context.Emit(OpCodes.Dup); - - context.EmitLdflg((int)PState.EBit); - - ILLabel lblBigEndian = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brtrue_S, lblBigEndian); - - // Little endian mode. - context.Emit(OpCodes.Conv_U4); - - EmitStoreToRegister(context, op.Rt); - - context.EmitLsr(32); - - context.Emit(OpCodes.Conv_U4); - - EmitStoreToRegister(context, op.Rt | 1); - - context.Emit(OpCodes.Br_S, lblEnd); - - // Big endian mode. - context.MarkLabel(lblBigEndian); - - context.EmitLsr(32); - - context.Emit(OpCodes.Conv_U4); - - EmitStoreToRegister(context, op.Rt); - - context.Emit(OpCodes.Conv_U4); - - EmitStoreToRegister(context, op.Rt | 1); - - context.MarkLabel(lblEnd); - } - else - { - EmitStoreToRegister(context, op.Rt); - } - } - else - { - if (op.WBack) - { - context.EmitLdtmp(); - - EmitStoreToRegister(context, op.Rn); - } - - EmitLoadFromRegister(context, op.Rt); - - if (size == DWordSizeLog2) - { - context.Emit(OpCodes.Conv_U8); - - context.EmitLdflg((int)PState.EBit); - - ILLabel lblBigEndian = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brtrue_S, lblBigEndian); - - // Little endian mode. - EmitLoadFromRegister(context, op.Rt | 1); - - context.Emit(OpCodes.Conv_U8); - - context.EmitLsl(32); - - context.Emit(OpCodes.Or); - - context.Emit(OpCodes.Br_S, lblEnd); - - // Big endian mode. - context.MarkLabel(lblBigEndian); - - context.EmitLsl(32); - - EmitLoadFromRegister(context, op.Rt | 1); - - context.Emit(OpCodes.Conv_U8); - - context.Emit(OpCodes.Or); - - context.MarkLabel(lblEnd); - } - - EmitWriteCall(context, size); - } - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitMemoryEx.cs b/ChocolArm64/Instructions/InstEmitMemoryEx.cs deleted file mode 100644 index 5deb035d..00000000 --- a/ChocolArm64/Instructions/InstEmitMemoryEx.cs +++ /dev/null @@ -1,350 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.Memory; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Threading; - -using static ChocolArm64.Instructions.InstEmitMemoryHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - [Flags] - private enum AccessType - { - None = 0, - Ordered = 1, - Exclusive = 2, - OrderedEx = Ordered | Exclusive - } - - public static void Clrex(ILEmitterCtx context) - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.ClearExclusiveAddress)); - } - - public static void Dmb(ILEmitterCtx context) => EmitBarrier(context); - public static void Dsb(ILEmitterCtx context) => EmitBarrier(context); - - public static void Ldar(ILEmitterCtx context) => EmitLdr(context, AccessType.Ordered); - public static void Ldaxr(ILEmitterCtx context) => EmitLdr(context, AccessType.OrderedEx); - public static void Ldxr(ILEmitterCtx context) => EmitLdr(context, AccessType.Exclusive); - public static void Ldxp(ILEmitterCtx context) => EmitLdp(context, AccessType.Exclusive); - public static void Ldaxp(ILEmitterCtx context) => EmitLdp(context, AccessType.OrderedEx); - - private static void EmitLdr(ILEmitterCtx context, AccessType accType) - { - EmitLoad(context, accType, pair: false); - } - - private static void EmitLdp(ILEmitterCtx context, AccessType accType) - { - EmitLoad(context, accType, pair: true); - } - - private static void EmitLoad(ILEmitterCtx context, AccessType accType, bool pair) - { - OpCodeMemEx64 op = (OpCodeMemEx64)context.CurrOp; - - bool ordered = (accType & AccessType.Ordered) != 0; - bool exclusive = (accType & AccessType.Exclusive) != 0; - - if (ordered) - { - EmitBarrier(context); - } - - context.EmitLdint(op.Rn); - context.EmitSttmp(); - - if (exclusive) - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdtmp(); - - context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.SetExclusiveAddress)); - } - - void WriteExclusiveValue(string propName) - { - context.Emit(OpCodes.Dup); - - if (op.Size < 3) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitSttmp2(); - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdtmp2(); - - context.EmitCallPrivatePropSet(typeof(CpuThreadState), propName); - } - - if (pair) - { - // Exclusive loads should be atomic. For pairwise loads, we need to - // read all the data at once. For a 32-bits pairwise load, we do a - // simple 64-bits load, for a 128-bits load, we need to call a special - // method to read 128-bits atomically. - if (op.Size == 2) - { - context.EmitLdtmp(); - - EmitReadZxCall(context, 3); - - context.Emit(OpCodes.Dup); - - // Mask low half. - context.Emit(OpCodes.Conv_U4); - - if (exclusive) - { - WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); - } - - context.EmitStintzr(op.Rt); - - // Shift high half. - context.EmitLsr(32); - context.Emit(OpCodes.Conv_U4); - - if (exclusive) - { - WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh)); - } - - context.EmitStintzr(op.Rt2); - } - else if (op.Size == 3) - { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdtmp(); - - context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicReadInt128)); - - context.Emit(OpCodes.Dup); - - // Load low part of the vector. - context.EmitLdc_I4(0); - context.EmitLdc_I4(3); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx)); - - if (exclusive) - { - WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); - } - - context.EmitStintzr(op.Rt); - - // Load high part of the vector. - context.EmitLdc_I4(1); - context.EmitLdc_I4(3); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx)); - - if (exclusive) - { - WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh)); - } - - context.EmitStintzr(op.Rt2); - } - else - { - throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes."); - } - } - else - { - // 8, 16, 32 or 64-bits (non-pairwise) load. - context.EmitLdtmp(); - - EmitReadZxCall(context, op.Size); - - if (exclusive) - { - WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); - } - - context.EmitStintzr(op.Rt); - } - } - - public static void Pfrm(ILEmitterCtx context) - { - // Memory Prefetch, execute as no-op. - } - - public static void Stlr(ILEmitterCtx context) => EmitStr(context, AccessType.Ordered); - public static void Stlxr(ILEmitterCtx context) => EmitStr(context, AccessType.OrderedEx); - public static void Stxr(ILEmitterCtx context) => EmitStr(context, AccessType.Exclusive); - public static void Stxp(ILEmitterCtx context) => EmitStp(context, AccessType.Exclusive); - public static void Stlxp(ILEmitterCtx context) => EmitStp(context, AccessType.OrderedEx); - - private static void EmitStr(ILEmitterCtx context, AccessType accType) - { - EmitStore(context, accType, pair: false); - } - - private static void EmitStp(ILEmitterCtx context, AccessType accType) - { - EmitStore(context, accType, pair: true); - } - - private static void EmitStore(ILEmitterCtx context, AccessType accType, bool pair) - { - OpCodeMemEx64 op = (OpCodeMemEx64)context.CurrOp; - - bool ordered = (accType & AccessType.Ordered) != 0; - bool exclusive = (accType & AccessType.Exclusive) != 0; - - if (ordered) - { - EmitBarrier(context); - } - - if (exclusive) - { - ILLabel lblEx = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdint(op.Rn); - - context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.CheckExclusiveAddress)); - - context.Emit(OpCodes.Brtrue_S, lblEx); - - // Address check failed, set error right away and do not store anything. - context.EmitLdc_I4(1); - context.EmitStintzr(op.Rs); - - context.Emit(OpCodes.Br, lblEnd); - - // Address check passed. - context.MarkLabel(lblEx); - - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdint(op.Rn); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCallPrivatePropGet(typeof(CpuThreadState), nameof(CpuThreadState.ExclusiveValueLow)); - - void EmitCast() - { - // The input should be always int64. - switch (op.Size) - { - case 0: context.Emit(OpCodes.Conv_U1); break; - case 1: context.Emit(OpCodes.Conv_U2); break; - case 2: context.Emit(OpCodes.Conv_U4); break; - } - } - - EmitCast(); - - if (pair) - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCallPrivatePropGet(typeof(CpuThreadState), nameof(CpuThreadState.ExclusiveValueHigh)); - - EmitCast(); - - context.EmitLdintzr(op.Rt); - - EmitCast(); - - context.EmitLdintzr(op.Rt2); - - EmitCast(); - - switch (op.Size) - { - case 2: context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchange2xInt32)); break; - case 3: context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt128)); break; - - default: throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes."); - } - } - else - { - context.EmitLdintzr(op.Rt); - - EmitCast(); - - switch (op.Size) - { - case 0: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeByte)); break; - case 1: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt16)); break; - case 2: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt32)); break; - case 3: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt64)); break; - - default: throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes."); - } - } - - // The value returned is a bool, true if the values compared - // were equal and the new value was written, false otherwise. - // We need to invert this result, as on ARM 1 indicates failure, - // and 0 success on those instructions. - context.EmitLdc_I4(1); - - context.Emit(OpCodes.Xor); - context.Emit(OpCodes.Dup); - context.Emit(OpCodes.Conv_U8); - - context.EmitStintzr(op.Rs); - - // Only clear the exclusive monitor if the store was successful (Rs = false). - context.Emit(OpCodes.Brtrue_S, lblEnd); - - Clrex(context); - - context.MarkLabel(lblEnd); - } - else - { - void EmitWriteCall(int rt, long offset) - { - context.EmitLdint(op.Rn); - - if (offset != 0) - { - context.EmitLdc_I8(offset); - - context.Emit(OpCodes.Add); - } - - context.EmitLdintzr(rt); - - InstEmitMemoryHelper.EmitWriteCall(context, op.Size); - } - - EmitWriteCall(op.Rt, 0); - - if (pair) - { - EmitWriteCall(op.Rt2, 1 << op.Size); - } - } - } - - private static void EmitBarrier(ILEmitterCtx context) - { - // Note: This barrier is most likely not necessary, and probably - // doesn't make any difference since we need to do a ton of stuff - // (software MMU emulation) to read or write anything anyway. - context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier)); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitMemoryHelper.cs b/ChocolArm64/Instructions/InstEmitMemoryHelper.cs deleted file mode 100644 index 08c8265b..00000000 --- a/ChocolArm64/Instructions/InstEmitMemoryHelper.cs +++ /dev/null @@ -1,475 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.Memory; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Runtime.Intrinsics.X86; - -namespace ChocolArm64.Instructions -{ - static class InstEmitMemoryHelper - { - private static int _tempIntAddress = ILEmitterCtx.GetIntTempIndex(); - private static int _tempIntValue = ILEmitterCtx.GetIntTempIndex(); - private static int _tempIntPtAddr = ILEmitterCtx.GetIntTempIndex(); - private static int _tempVecValue = ILEmitterCtx.GetVecTempIndex(); - - private enum Extension - { - Zx, - Sx32, - Sx64 - } - - public static void EmitReadZxCall(ILEmitterCtx context, int size) - { - EmitReadCall(context, Extension.Zx, size); - } - - public static void EmitReadSx32Call(ILEmitterCtx context, int size) - { - EmitReadCall(context, Extension.Sx32, size); - } - - public static void EmitReadSx64Call(ILEmitterCtx context, int size) - { - EmitReadCall(context, Extension.Sx64, size); - } - - private static void EmitReadCall(ILEmitterCtx context, Extension ext, int size) - { - // Save the address into a temp. - context.EmitStint(_tempIntAddress); - - bool isSimd = IsSimd(context); - - if (size < 0 || size > (isSimd ? 4 : 3)) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - if (isSimd) - { - if (context.Tier == TranslationTier.Tier0 || !Sse2.IsSupported || size < 2) - { - EmitReadVectorFallback(context, size); - } - else - { - EmitReadVector(context, size); - } - } - else - { - if (context.Tier == TranslationTier.Tier0) - { - EmitReadIntFallback(context, size); - } - else - { - EmitReadInt(context, size); - } - } - - if (!isSimd) - { - if (ext == Extension.Sx32 || - ext == Extension.Sx64) - { - switch (size) - { - case 0: context.Emit(OpCodes.Conv_I1); break; - case 1: context.Emit(OpCodes.Conv_I2); break; - case 2: context.Emit(OpCodes.Conv_I4); break; - } - } - - if (size < 3) - { - context.Emit(ext == Extension.Sx64 - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8); - } - } - } - - public static void EmitWriteCall(ILEmitterCtx context, int size) - { - bool isSimd = IsSimd(context); - - // Save the value into a temp. - if (isSimd) - { - context.EmitStvec(_tempVecValue); - } - else - { - context.EmitStint(_tempIntValue); - } - - // Save the address into a temp. - context.EmitStint(_tempIntAddress); - - if (size < 0 || size > (isSimd ? 4 : 3)) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - if (isSimd) - { - if (context.Tier == TranslationTier.Tier0 || !Sse2.IsSupported || size < 2) - { - EmitWriteVectorFallback(context, size); - } - else - { - EmitWriteVector(context, size); - } - } - else - { - if (context.Tier == TranslationTier.Tier0) - { - EmitWriteIntFallback(context, size); - } - else - { - EmitWriteInt(context, size); - } - } - } - - private static bool IsSimd(ILEmitterCtx context) - { - return context.CurrOp is IOpCodeSimd64 && - !(context.CurrOp is OpCodeSimdMemMs64 || - context.CurrOp is OpCodeSimdMemSs64); - } - - private static void EmitReadInt(ILEmitterCtx context, int size) - { - EmitAddressCheck(context, size); - - ILLabel lblFastPath = new ILLabel(); - ILLabel lblSlowPath = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brfalse_S, lblFastPath); - - context.MarkLabel(lblSlowPath); - - EmitReadIntFallback(context, size); - - context.Emit(OpCodes.Br, lblEnd); - - context.MarkLabel(lblFastPath); - - EmitPtPointerLoad(context, lblSlowPath); - - switch (size) - { - case 0: context.Emit(OpCodes.Ldind_U1); break; - case 1: context.Emit(OpCodes.Ldind_U2); break; - case 2: context.Emit(OpCodes.Ldind_U4); break; - case 3: context.Emit(OpCodes.Ldind_I8); break; - } - - context.MarkLabel(lblEnd); - } - - private static void EmitReadVector(ILEmitterCtx context, int size) - { - EmitAddressCheck(context, size); - - ILLabel lblFastPath = new ILLabel(); - ILLabel lblSlowPath = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brfalse_S, lblFastPath); - - context.MarkLabel(lblSlowPath); - - EmitReadVectorFallback(context, size); - - context.Emit(OpCodes.Br, lblEnd); - - context.MarkLabel(lblFastPath); - - EmitPtPointerLoad(context, lblSlowPath); - - switch (size) - { - case 2: context.EmitCall(typeof(Sse), nameof(Sse.LoadScalarVector128)); break; - - case 3: - { - Type[] types = new Type[] { typeof(double*) }; - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.LoadScalarVector128), types)); - - break; - } - - case 4: context.EmitCall(typeof(Sse), nameof(Sse.LoadAlignedVector128)); break; - - throw new InvalidOperationException($"Invalid vector load size of {1 << size} bytes."); - } - - context.MarkLabel(lblEnd); - } - - private static void EmitWriteInt(ILEmitterCtx context, int size) - { - EmitAddressCheck(context, size); - - ILLabel lblFastPath = new ILLabel(); - ILLabel lblSlowPath = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brfalse_S, lblFastPath); - - context.MarkLabel(lblSlowPath); - - EmitWriteIntFallback(context, size); - - context.Emit(OpCodes.Br, lblEnd); - - context.MarkLabel(lblFastPath); - - EmitPtPointerLoad(context, lblSlowPath); - - context.EmitLdint(_tempIntValue); - - if (size < 3) - { - context.Emit(OpCodes.Conv_U4); - } - - switch (size) - { - case 0: context.Emit(OpCodes.Stind_I1); break; - case 1: context.Emit(OpCodes.Stind_I2); break; - case 2: context.Emit(OpCodes.Stind_I4); break; - case 3: context.Emit(OpCodes.Stind_I8); break; - } - - context.MarkLabel(lblEnd); - } - - private static void EmitWriteVector(ILEmitterCtx context, int size) - { - EmitAddressCheck(context, size); - - ILLabel lblFastPath = new ILLabel(); - ILLabel lblSlowPath = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.Brfalse_S, lblFastPath); - - context.MarkLabel(lblSlowPath); - - EmitWriteVectorFallback(context, size); - - context.Emit(OpCodes.Br, lblEnd); - - context.MarkLabel(lblFastPath); - - EmitPtPointerLoad(context, lblSlowPath); - - context.EmitLdvec(_tempVecValue); - - switch (size) - { - case 2: context.EmitCall(typeof(Sse), nameof(Sse.StoreScalar)); break; - case 3: context.EmitCall(typeof(Sse2), nameof(Sse2.StoreScalar)); break; - case 4: context.EmitCall(typeof(Sse), nameof(Sse.StoreAligned)); break; - - default: throw new InvalidOperationException($"Invalid vector store size of {1 << size} bytes."); - } - - context.MarkLabel(lblEnd); - } - - private static void EmitAddressCheck(ILEmitterCtx context, int size) - { - long addressCheckMask = ~(context.Memory.AddressSpaceSize - 1); - - addressCheckMask |= (1u << size) - 1; - - context.EmitLdint(_tempIntAddress); - - context.EmitLdc_I(addressCheckMask); - - context.Emit(OpCodes.And); - } - - private static void EmitPtPointerLoad(ILEmitterCtx context, ILLabel lblFallbackPath) - { - context.EmitLdc_I8(context.Memory.PageTable.ToInt64()); - - context.Emit(OpCodes.Conv_I); - - int bit = MemoryManager.PageBits; - - do - { - context.EmitLdint(_tempIntAddress); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitLsr(bit); - - bit += context.Memory.PtLevelBits; - - if (bit < context.Memory.AddressSpaceBits) - { - context.EmitLdc_I8(context.Memory.PtLevelMask); - - context.Emit(OpCodes.And); - } - - context.EmitLdc_I8(IntPtr.Size); - - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Conv_I); - context.Emit(OpCodes.Add); - context.Emit(OpCodes.Ldind_I); - } - while (bit < context.Memory.AddressSpaceBits); - - if (!context.Memory.HasWriteWatchSupport) - { - context.Emit(OpCodes.Conv_U8); - - context.EmitStint(_tempIntPtAddr); - context.EmitLdint(_tempIntPtAddr); - - context.EmitLdc_I8(MemoryManager.PteFlagsMask); - - context.Emit(OpCodes.And); - - context.Emit(OpCodes.Brtrue, lblFallbackPath); - - context.EmitLdint(_tempIntPtAddr); - - context.Emit(OpCodes.Conv_I); - } - - context.EmitLdint(_tempIntAddress); - - context.EmitLdc_I(MemoryManager.PageMask); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Conv_I); - context.Emit(OpCodes.Add); - } - - private static void EmitReadIntFallback(ILEmitterCtx context, int size) - { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdint(_tempIntAddress); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - string fallbackMethodName = null; - - switch (size) - { - case 0: fallbackMethodName = nameof(MemoryManager.ReadByte); break; - case 1: fallbackMethodName = nameof(MemoryManager.ReadUInt16); break; - case 2: fallbackMethodName = nameof(MemoryManager.ReadUInt32); break; - case 3: fallbackMethodName = nameof(MemoryManager.ReadUInt64); break; - } - - context.EmitCall(typeof(MemoryManager), fallbackMethodName); - } - - private static void EmitReadVectorFallback(ILEmitterCtx context, int size) - { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdint(_tempIntAddress); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - string fallbackMethodName = null; - - switch (size) - { - case 0: fallbackMethodName = nameof(MemoryManager.ReadVector8); break; - case 1: fallbackMethodName = nameof(MemoryManager.ReadVector16); break; - case 2: fallbackMethodName = nameof(MemoryManager.ReadVector32); break; - case 3: fallbackMethodName = nameof(MemoryManager.ReadVector64); break; - case 4: fallbackMethodName = nameof(MemoryManager.ReadVector128); break; - } - - context.EmitCall(typeof(MemoryManager), fallbackMethodName); - } - - private static void EmitWriteIntFallback(ILEmitterCtx context, int size) - { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdint(_tempIntAddress); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitLdint(_tempIntValue); - - if (size < 3) - { - context.Emit(OpCodes.Conv_U4); - } - - string fallbackMethodName = null; - - switch (size) - { - case 0: fallbackMethodName = nameof(MemoryManager.WriteByte); break; - case 1: fallbackMethodName = nameof(MemoryManager.WriteUInt16); break; - case 2: fallbackMethodName = nameof(MemoryManager.WriteUInt32); break; - case 3: fallbackMethodName = nameof(MemoryManager.WriteUInt64); break; - } - - context.EmitCall(typeof(MemoryManager), fallbackMethodName); - } - - private static void EmitWriteVectorFallback(ILEmitterCtx context, int size) - { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdint(_tempIntAddress); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitLdvec(_tempVecValue); - - string fallbackMethodName = null; - - switch (size) - { - case 0: fallbackMethodName = nameof(MemoryManager.WriteVector8); break; - case 1: fallbackMethodName = nameof(MemoryManager.WriteVector16); break; - case 2: fallbackMethodName = nameof(MemoryManager.WriteVector32); break; - case 3: fallbackMethodName = nameof(MemoryManager.WriteVector64); break; - case 4: fallbackMethodName = nameof(MemoryManager.WriteVector128Internal); break; - } - - context.EmitCall(typeof(MemoryManager), fallbackMethodName); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitMove.cs b/ChocolArm64/Instructions/InstEmitMove.cs deleted file mode 100644 index be3e8e2d..00000000 --- a/ChocolArm64/Instructions/InstEmitMove.cs +++ /dev/null @@ -1,41 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Movk(ILEmitterCtx context) - { - OpCodeMov64 op = (OpCodeMov64)context.CurrOp; - - context.EmitLdintzr(op.Rd); - context.EmitLdc_I(~(0xffffL << op.Pos)); - - context.Emit(OpCodes.And); - - context.EmitLdc_I(op.Imm); - - context.Emit(OpCodes.Or); - - context.EmitStintzr(op.Rd); - } - - public static void Movn(ILEmitterCtx context) - { - OpCodeMov64 op = (OpCodeMov64)context.CurrOp; - - context.EmitLdc_I(~op.Imm); - context.EmitStintzr(op.Rd); - } - - public static void Movz(ILEmitterCtx context) - { - OpCodeMov64 op = (OpCodeMov64)context.CurrOp; - - context.EmitLdc_I(op.Imm); - context.EmitStintzr(op.Rd); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitMul.cs b/ChocolArm64/Instructions/InstEmitMul.cs deleted file mode 100644 index b7418e69..00000000 --- a/ChocolArm64/Instructions/InstEmitMul.cs +++ /dev/null @@ -1,80 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Madd(ILEmitterCtx context) => EmitMul(context, OpCodes.Add); - public static void Msub(ILEmitterCtx context) => EmitMul(context, OpCodes.Sub); - - private static void EmitMul(ILEmitterCtx context, OpCode ilOp) - { - OpCodeMul64 op = (OpCodeMul64)context.CurrOp; - - context.EmitLdintzr(op.Ra); - context.EmitLdintzr(op.Rn); - context.EmitLdintzr(op.Rm); - - context.Emit(OpCodes.Mul); - context.Emit(ilOp); - - context.EmitStintzr(op.Rd); - } - - public static void Smaddl(ILEmitterCtx context) => EmitMull(context, OpCodes.Add, true); - public static void Smsubl(ILEmitterCtx context) => EmitMull(context, OpCodes.Sub, true); - public static void Umaddl(ILEmitterCtx context) => EmitMull(context, OpCodes.Add, false); - public static void Umsubl(ILEmitterCtx context) => EmitMull(context, OpCodes.Sub, false); - - private static void EmitMull(ILEmitterCtx context, OpCode addSubOp, bool signed) - { - OpCodeMul64 op = (OpCodeMul64)context.CurrOp; - - OpCode castOp = signed - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8; - - context.EmitLdintzr(op.Ra); - context.EmitLdintzr(op.Rn); - - context.Emit(OpCodes.Conv_I4); - context.Emit(castOp); - - context.EmitLdintzr(op.Rm); - - context.Emit(OpCodes.Conv_I4); - context.Emit(castOp); - context.Emit(OpCodes.Mul); - - context.Emit(addSubOp); - - context.EmitStintzr(op.Rd); - } - - public static void Smulh(ILEmitterCtx context) - { - OpCodeMul64 op = (OpCodeMul64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - context.EmitLdintzr(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.SMulHi128)); - - context.EmitStintzr(op.Rd); - } - - public static void Umulh(ILEmitterCtx context) - { - OpCodeMul64 op = (OpCodeMul64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - context.EmitLdintzr(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.UMulHi128)); - - context.EmitStintzr(op.Rd); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs deleted file mode 100644 index fa9666eb..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs +++ /dev/null @@ -1,3797 +0,0 @@ -// https://github.com/intel/ARM_NEON_2_x86_SSE/blob/master/NEON_2_SSE.h -// https://www.agner.org/optimize/#vectorclass @ vectori128.h - -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Abs_S(ILEmitterCtx context) - { - EmitScalarUnaryOpSx(context, () => EmitAbs(context)); - } - - public static void Abs_V(ILEmitterCtx context) - { - EmitVectorUnaryOpSx(context, () => EmitAbs(context)); - } - - public static void Add_S(ILEmitterCtx context) - { - EmitScalarBinaryOpZx(context, () => context.Emit(OpCodes.Add)); - } - - public static void Add_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - EmitSse2Op(context, nameof(Sse2.Add)); - } - else - { - EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Add)); - } - } - - public static void Addhn_V(ILEmitterCtx context) - { - EmitHighNarrow(context, () => context.Emit(OpCodes.Add), round: false); - } - - public static void Addp_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - EmitVectorExtractZx(context, op.Rn, 0, op.Size); - EmitVectorExtractZx(context, op.Rn, 1, op.Size); - - context.Emit(OpCodes.Add); - - EmitScalarSet(context, op.Rd, op.Size); - } - - public static void Addp_V(ILEmitterCtx context) - { - EmitVectorPairwiseOpZx(context, () => context.Emit(OpCodes.Add)); - } - - public static void Addv_V(ILEmitterCtx context) - { - EmitVectorAcrossVectorOpZx(context, () => context.Emit(OpCodes.Add)); - } - - public static void Cls_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - int eSize = 8 << op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - - context.EmitLdc_I4(eSize); - - SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingSigns)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Clz_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - int eSize = 8 << op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - - if (Lzcnt.IsSupported && eSize == 32) - { - context.Emit(OpCodes.Conv_U4); - - context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { typeof(uint) })); - - context.Emit(OpCodes.Conv_U8); - } - else - { - context.EmitLdc_I4(eSize); - - SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingZeros)); - } - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Cnt_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, 0); - - if (Popcnt.IsSupported) - { - context.EmitCall(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { typeof(ulong) })); - } - else - { - SoftFallback.EmitCall(context, nameof(SoftFallback.CountSetBits8)); - } - - EmitVectorInsert(context, op.Rd, index, 0); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Fabd_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSsv = new Type[] { typeof(float) }; - Type[] typesSubAnt = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(-0f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), typesSubAnt)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAnt)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (sizeF == 1) */ - { - Type[] typesSsv = new Type[] { typeof(double) }; - Type[] typesSubAnt = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(-0d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesSubAnt)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAnt)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub)); - - EmitUnaryMathCall(context, nameof(Math.Abs)); - }); - } - } - - public static void Fabd_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSav = new Type[] { typeof(float) }; - Type[] typesSubAnt = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(-0f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesSubAnt)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAnt)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSav = new Type[] { typeof(double) }; - Type[] typesSubAnt = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(-0d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAnt)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAnt)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub)); - - EmitUnaryMathCall(context, nameof(Math.Abs)); - }); - } - } - - public static void Fabs_S(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - if (op.Size == 0) - { - Type[] typesSsv = new Type[] { typeof(float) }; - Type[] typesAnt = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(-0f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (op.Size == 1) */ - { - Type[] typesSsv = new Type[] { typeof(double) }; - Type[] typesAnt = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(-0d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Abs)); - }); - } - } - - public static void Fabs_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSav = new Type[] { typeof(float) }; - Type[] typesAnt = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(-0f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSav = new Type[] { typeof(double) }; - Type[] typesAnt = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(-0d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Abs)); - }); - } - } - - public static void Fadd_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.AddScalar)); - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd)); - }); - } - } - - public static void Fadd_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Add)); - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd)); - }); - } - } - - public static void Faddp_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse3) - { - if (sizeF == 0) - { - Type[] typesAddH = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse3).GetMethod(nameof(Sse3.HorizontalAdd), typesAddH)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (sizeF == 1) */ - { - Type[] typesAddH = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse3).GetMethod(nameof(Sse3.HorizontalAdd), typesAddH)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorExtractF(context, op.Rn, 0, sizeF); - EmitVectorExtractF(context, op.Rn, 1, sizeF); - - EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd)); - - EmitScalarSetF(context, op.Rd, sizeF); - } - } - - public static void Faddp_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorPairwiseSseOrSse2OpF(context, nameof(Sse.Add)); - } - else - { - EmitVectorPairwiseOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd)); - }); - } - } - - public static void Fdiv_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.DivideScalar)); - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv)); - }); - } - } - - public static void Fdiv_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Divide)); - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv)); - }); - } - } - - public static void Fmadd_S(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (op.Size == 0) - { - Type[] typesMulAdd = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Ra); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), typesMulAdd)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AddScalar), typesMulAdd)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (op.Size == 1) */ - { - Type[] typesMulAdd = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Ra); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AddScalar), typesMulAdd)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitScalarTernaryRaOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd)); - }); - } - } - - public static void Fmax_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.MaxScalar)); - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax)); - }); - } - } - - public static void Fmax_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Max)); - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax)); - }); - } - } - - public static void Fmaxnm_S(ILEmitterCtx context) - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum)); - }); - } - - public static void Fmaxnm_V(ILEmitterCtx context) - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum)); - }); - } - - public static void Fmaxp_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorPairwiseSseOrSse2OpF(context, nameof(Sse.Max)); - } - else - { - EmitVectorPairwiseOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax)); - }); - } - } - - public static void Fmin_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.MinScalar)); - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin)); - }); - } - } - - public static void Fmin_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Min)); - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin)); - }); - } - } - - public static void Fminnm_S(ILEmitterCtx context) - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum)); - }); - } - - public static void Fminnm_V(ILEmitterCtx context) - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum)); - }); - } - - public static void Fminp_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorPairwiseSseOrSse2OpF(context, nameof(Sse.Min)); - } - else - { - EmitVectorPairwiseOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin)); - }); - } - } - - public static void Fmla_Se(ILEmitterCtx context) - { - EmitScalarTernaryOpByElemF(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); - } - - public static void Fmla_V(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesMulAdd = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Add), typesMulAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesMulAdd = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorTernaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd)); - }); - } - } - - public static void Fmla_Ve(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdRegElemF64 op = (OpCodeSimdRegElemF64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSfl = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>), typeof(byte) }; - Type[] typesMulAdd = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Add), typesMulAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSfl = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>), typeof(byte) }; - Type[] typesMulAdd = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorTernaryOpByElemF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd)); - }); - } - } - - public static void Fmls_Se(ILEmitterCtx context) - { - EmitScalarTernaryOpByElemF(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); - } - - public static void Fmls_V(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesMulSub = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesMulSub = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorTernaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub)); - }); - } - } - - public static void Fmls_Ve(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdRegElemF64 op = (OpCodeSimdRegElemF64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSfl = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>), typeof(byte) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSfl = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>), typeof(byte) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorTernaryOpByElemF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub)); - }); - } - } - - public static void Fmsub_S(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (op.Size == 0) - { - Type[] typesMulSub = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Ra); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), typesMulSub)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (op.Size == 1) */ - { - Type[] typesMulSub = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Ra); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesMulSub)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitScalarTernaryRaOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub)); - }); - } - } - - public static void Fmul_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.MultiplyScalar)); - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul)); - }); - } - } - - public static void Fmul_Se(ILEmitterCtx context) - { - EmitScalarBinaryOpByElemF(context, () => context.Emit(OpCodes.Mul)); - } - - public static void Fmul_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Multiply)); - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul)); - }); - } - } - - public static void Fmul_Ve(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdRegElemF64 op = (OpCodeSimdRegElemF64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSfl = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>), typeof(byte) }; - Type[] typesMul = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rn); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMul)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSfl = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>), typeof(byte) }; - Type[] typesMul = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rn); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMul)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorBinaryOpByElemF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul)); - }); - } - } - - public static void Fmulx_S(ILEmitterCtx context) - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX)); - }); - } - - public static void Fmulx_Se(ILEmitterCtx context) - { - EmitScalarBinaryOpByElemF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX)); - }); - } - - public static void Fmulx_V(ILEmitterCtx context) - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX)); - }); - } - - public static void Fmulx_Ve(ILEmitterCtx context) - { - EmitVectorBinaryOpByElemF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX)); - }); - } - - public static void Fneg_S(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - if (op.Size == 0) - { - Type[] typesSsv = new Type[] { typeof(float) }; - Type[] typesXor = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(-0f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Xor), typesXor)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (op.Size == 1) */ - { - Type[] typesSsv = new Type[] { typeof(double) }; - Type[] typesXor = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(-0d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXor)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitScalarUnaryOpF(context, () => context.Emit(OpCodes.Neg)); - } - } - - public static void Fneg_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSav = new Type[] { typeof(float) }; - Type[] typesXor = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(-0f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Xor), typesXor)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSav = new Type[] { typeof(double) }; - Type[] typesXor = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(-0d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXor)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorUnaryOpF(context, () => context.Emit(OpCodes.Neg)); - } - } - - public static void Fnmadd_S(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - EmitVectorExtractF(context, op.Rn, 0, sizeF); - - context.Emit(OpCodes.Neg); - - EmitVectorExtractF(context, op.Rm, 0, sizeF); - - context.Emit(OpCodes.Mul); - - EmitVectorExtractF(context, op.Ra, 0, sizeF); - - context.Emit(OpCodes.Sub); - - EmitScalarSetF(context, op.Rd, sizeF); - } - - public static void Fnmsub_S(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - EmitVectorExtractF(context, op.Rn, 0, sizeF); - EmitVectorExtractF(context, op.Rm, 0, sizeF); - - context.Emit(OpCodes.Mul); - - EmitVectorExtractF(context, op.Ra, 0, sizeF); - - context.Emit(OpCodes.Sub); - - EmitScalarSetF(context, op.Rd, sizeF); - } - - public static void Fnmul_S(ILEmitterCtx context) - { - EmitScalarBinaryOpF(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Neg); - }); - } - - public static void Frecpe_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.ReciprocalScalar)); - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipEstimate)); - }); - } - } - - public static void Frecpe_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Reciprocal)); - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipEstimate)); - }); - } - } - - public static void Frecps_S(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSsv = new Type[] { typeof(float) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(2f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), typesMulSub)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (sizeF == 1) */ - { - Type[] typesSsv = new Type[] { typeof(double) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(2d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesMulSub)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStepFused)); - }); - } - } - - public static void Frecps_V(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSav = new Type[] { typeof(float) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(2f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSav = new Type[] { typeof(double) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(2d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStepFused)); - }); - } - } - - public static void Frecpx_S(ILEmitterCtx context) - { - EmitScalarUnaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecpX)); - }); - } - - public static void Frinta_S(ILEmitterCtx context) - { - EmitScalarUnaryOpF(context, () => - { - EmitRoundMathCall(context, MidpointRounding.AwayFromZero); - }); - } - - public static void Frinta_V(ILEmitterCtx context) - { - EmitVectorUnaryOpF(context, () => - { - EmitRoundMathCall(context, MidpointRounding.AwayFromZero); - }); - } - - public static void Frinti_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - if (Optimizations.UseSse41) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(op.Rn); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (op.Size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41ScalarRoundF)); - } - else /* if (op.Size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41ScalarRound)); - } - - context.EmitStvec(op.Rd); - } - else - { - EmitScalarUnaryOpF(context, () => - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (op.Size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.RoundF)); - } - else /* if (op.Size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Round)); - } - }); - } - } - - public static void Frinti_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse41) - { - context.EmitLdvec(op.Rn); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41VectorRoundF)); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41VectorRound)); - } - - context.EmitStvec(op.Rd); - - if (sizeF == 0 && op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorUnaryOpF(context, () => - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.RoundF)); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Round)); - } - }); - } - } - - public static void Frintm_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.TowardsMinusInfinity, scalar: true); - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Floor)); - }); - } - } - - public static void Frintm_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.TowardsMinusInfinity, scalar: false); - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Floor)); - }); - } - } - - public static void Frintn_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.ToNearest, scalar: true); - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitRoundMathCall(context, MidpointRounding.ToEven); - }); - } - } - - public static void Frintn_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.ToNearest, scalar: false); - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitRoundMathCall(context, MidpointRounding.ToEven); - }); - } - } - - public static void Frintp_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.TowardsPlusInfinity, scalar: true); - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Ceiling)); - }); - } - } - - public static void Frintp_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.TowardsPlusInfinity, scalar: false); - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Ceiling)); - }); - } - } - - public static void Frintx_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - if (Optimizations.UseSse41) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(op.Rn); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (op.Size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41ScalarRoundF)); - } - else /* if (op.Size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41ScalarRound)); - } - - context.EmitStvec(op.Rd); - } - else - { - EmitScalarUnaryOpF(context, () => - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (op.Size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.RoundF)); - } - else /* if (op.Size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Round)); - } - }); - } - } - - public static void Frintx_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse41) - { - context.EmitLdvec(op.Rn); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41VectorRoundF)); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41VectorRound)); - } - - context.EmitStvec(op.Rd); - - if (sizeF == 0 && op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorUnaryOpF(context, () => - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.RoundF)); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.Round)); - } - }); - } - } - - public static void Frintz_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.TowardsZero, scalar: true); - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Truncate)); - }); - } - } - - public static void Frintz_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Frint(context, RoundMode.TowardsZero, scalar: false); - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitUnaryMathCall(context, nameof(Math.Truncate)); - }); - } - } - - public static void Frsqrte_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.ReciprocalSqrtScalar)); - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtEstimate)); - }); - } - } - - public static void Frsqrte_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.ReciprocalSqrt)); - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtEstimate)); - }); - } - } - - public static void Frsqrts_S(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSsv = new Type[] { typeof(float) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(0.5f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); - - context.EmitLdc_R4(3f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), typesMulSub)); - - context.EmitStvec(op.Rd); - - EmitVectorZero32_128(context, op.Rd); - } - else /* if (sizeF == 1) */ - { - Type[] typesSsv = new Type[] { typeof(double) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(0.5d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - - context.EmitLdc_R8(3d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); - - context.EmitStvec(op.Rd); - - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused)); - }); - } - } - - public static void Frsqrts_V(ILEmitterCtx context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] typesSav = new Type[] { typeof(float) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdc_R4(0.5f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); - - context.EmitLdc_R4(3f); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulSub)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] typesSav = new Type[] { typeof(double) }; - Type[] typesMulSub = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdc_R8(0.5d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitLdc_R8(3d); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); - - context.EmitStvec(op.Rd); - } - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused)); - }); - } - } - - public static void Fsqrt_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.SqrtScalar)); - } - else - { - EmitScalarUnaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt)); - }); - } - } - - public static void Fsqrt_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Sqrt)); - } - else - { - EmitVectorUnaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt)); - }); - } - } - - public static void Fsub_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarSseOrSse2OpF(context, nameof(Sse.SubtractScalar)); - } - else - { - EmitScalarBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub)); - }); - } - } - - public static void Fsub_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorSseOrSse2OpF(context, nameof(Sse.Subtract)); - } - else - { - EmitVectorBinaryOpF(context, () => - { - EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub)); - }); - } - } - - public static void Mla_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Mul_AddSub(context, nameof(Sse2.Add)); - } - else - { - EmitVectorTernaryOpZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); - } - } - - public static void Mla_Ve(ILEmitterCtx context) - { - EmitVectorTernaryOpByElemZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); - } - - public static void Mls_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Mul_AddSub(context, nameof(Sse2.Subtract)); - } - else - { - EmitVectorTernaryOpZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); - } - } - - public static void Mls_Ve(ILEmitterCtx context) - { - EmitVectorTernaryOpByElemZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); - } - - public static void Mul_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Mul_AddSub(context); - } - else - { - EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Mul)); - } - } - - public static void Mul_Ve(ILEmitterCtx context) - { - EmitVectorBinaryOpByElemZx(context, () => context.Emit(OpCodes.Mul)); - } - - public static void Neg_S(ILEmitterCtx context) - { - EmitScalarUnaryOpSx(context, () => context.Emit(OpCodes.Neg)); - } - - public static void Neg_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorUnaryOpSx(context, () => context.Emit(OpCodes.Neg)); - } - } - - public static void Raddhn_V(ILEmitterCtx context) - { - EmitHighNarrow(context, () => context.Emit(OpCodes.Add), round: true); - } - - public static void Rsubhn_V(ILEmitterCtx context) - { - EmitHighNarrow(context, () => context.Emit(OpCodes.Sub), round: true); - } - - public static void Saba_V(ILEmitterCtx context) - { - EmitVectorTernaryOpSx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - - context.Emit(OpCodes.Add); - }); - } - - public static void Sabal_V(ILEmitterCtx context) - { - EmitVectorWidenRnRmTernaryOpSx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - - context.Emit(OpCodes.Add); - }); - } - - public static void Sabd_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesAndOr = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSub)); - - context.EmitStvectmp(); // Cmp mask - context.EmitLdvectmp(); // Cmp mask - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); - - context.EmitLdvectmp(); // Cmp mask - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpSx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); - } - } - - public static void Sabdl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], - VectorIntTypesPerSizeLog2[op.Size + 1] }; - Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAndOr = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - - string nameCvt = op.Size == 0 - ? nameof(Sse41.ConvertToVector128Int16) - : nameof(Sse41.ConvertToVector128Int32); - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitStvectmp2(); // Long Rm - context.EmitStvectmp(); // Long Rn - - context.EmitLdvectmp(); // Long Rn - context.EmitLdvectmp2(); // Long Rm - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSub)); - - context.EmitStvectmp3(); // Cmp mask - context.EmitLdvectmp3(); // Cmp mask - - context.EmitLdvectmp(); // Long Rn - context.EmitLdvectmp2(); // Long Rm - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); - - context.EmitLdvectmp3(); // Cmp mask - - context.EmitLdvectmp2(); // Long Rm - context.EmitLdvectmp(); // Long Rn - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmBinaryOpSx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); - } - } - - public static void Sadalp_V(ILEmitterCtx context) - { - EmitAddLongPairwise(context, signed: true, accumulate: true); - } - - public static void Saddl_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], - VectorIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmBinaryOpSx(context, () => context.Emit(OpCodes.Add)); - } - } - - public static void Saddlp_V(ILEmitterCtx context) - { - EmitAddLongPairwise(context, signed: true, accumulate: false); - } - - public static void Saddlv_V(ILEmitterCtx context) - { - EmitVectorLongAcrossVectorOpSx(context, () => context.Emit(OpCodes.Add)); - } - - public static void Saddw_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], - VectorIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRmBinaryOpSx(context, () => context.Emit(OpCodes.Add)); - } - } - - public static void Shadd_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAndXorAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXorAdd)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXorAdd)); - - context.Emit(OpCodes.Ldc_I4_1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpSx(context, () => - { - context.Emit(OpCodes.Add); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr); - }); - } - } - - public static void Shsub_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Type[] typesSav = new Type[] { IntTypesPerSizeLog2[op.Size] }; - Type[] typesAddSub = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; - Type[] typesAvg = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdc_I4(op.Size == 0 ? sbyte.MinValue : short.MinValue); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvectmp(); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAddSub)); - - context.Emit(OpCodes.Dup); - - context.EmitLdvec(op.Rm); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAddSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesAddSub)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpSx(context, () => - { - context.Emit(OpCodes.Sub); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr); - }); - } - } - - public static void Smax_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesMax = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - Type typeSse = op.Size == 1 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - Type[] types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types); - - EmitVectorBinaryOpSx(context, () => context.EmitCall(mthdInfo)); - } - } - - public static void Smaxp_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types); - - EmitVectorPairwiseOpSx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Smaxv_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types); - - EmitVectorAcrossVectorOpSx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Smin_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesMin = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - Type typeSse = op.Size == 1 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.Min), typesMin)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - Type[] types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types); - - EmitVectorBinaryOpSx(context, () => context.EmitCall(mthdInfo)); - } - } - - public static void Sminp_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types); - - EmitVectorPairwiseOpSx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Sminv_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types); - - EmitVectorAcrossVectorOpSx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Smlal_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesMulAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], - VectorIntTypesPerSizeLog2[op.Size + 1] }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - string nameCvt = op.Size == 0 - ? nameof(Sse41.ConvertToVector128Int16) - : nameof(Sse41.ConvertToVector128Int32); - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.MultiplyLow), typesMulAdd)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmTernaryOpSx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); - } - } - - public static void Smlal_Ve(ILEmitterCtx context) - { - EmitVectorWidenTernaryOpByElemSx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); - } - - public static void Smlsl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesMulSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], - VectorIntTypesPerSizeLog2[op.Size + 1] }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - string nameCvt = op.Size == 0 - ? nameof(Sse41.ConvertToVector128Int16) - : nameof(Sse41.ConvertToVector128Int32); - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.MultiplyLow), typesMulSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmTernaryOpSx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); - } - } - - public static void Smlsl_Ve(ILEmitterCtx context) - { - EmitVectorWidenTernaryOpByElemSx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); - } - - public static void Smull_V(ILEmitterCtx context) - { - EmitVectorWidenRnRmBinaryOpSx(context, () => context.Emit(OpCodes.Mul)); - } - - public static void Smull_Ve(ILEmitterCtx context) - { - EmitVectorWidenBinaryOpByElemSx(context, () => context.Emit(OpCodes.Mul)); - } - - public static void Sqabs_S(ILEmitterCtx context) - { - EmitScalarSaturatingUnaryOpSx(context, () => EmitAbs(context)); - } - - public static void Sqabs_V(ILEmitterCtx context) - { - EmitVectorSaturatingUnaryOpSx(context, () => EmitAbs(context)); - } - - public static void Sqadd_S(ILEmitterCtx context) - { - EmitScalarSaturatingBinaryOpSx(context, SaturatingFlags.Add); - } - - public static void Sqadd_V(ILEmitterCtx context) - { - EmitVectorSaturatingBinaryOpSx(context, SaturatingFlags.Add); - } - - public static void Sqdmulh_S(ILEmitterCtx context) - { - EmitSaturatingBinaryOp(context, () => EmitDoublingMultiplyHighHalf(context, round: false), SaturatingFlags.ScalarSx); - } - - public static void Sqdmulh_V(ILEmitterCtx context) - { - EmitSaturatingBinaryOp(context, () => EmitDoublingMultiplyHighHalf(context, round: false), SaturatingFlags.VectorSx); - } - - public static void Sqneg_S(ILEmitterCtx context) - { - EmitScalarSaturatingUnaryOpSx(context, () => context.Emit(OpCodes.Neg)); - } - - public static void Sqneg_V(ILEmitterCtx context) - { - EmitVectorSaturatingUnaryOpSx(context, () => context.Emit(OpCodes.Neg)); - } - - public static void Sqrdmulh_S(ILEmitterCtx context) - { - EmitSaturatingBinaryOp(context, () => EmitDoublingMultiplyHighHalf(context, round: true), SaturatingFlags.ScalarSx); - } - - public static void Sqrdmulh_V(ILEmitterCtx context) - { - EmitSaturatingBinaryOp(context, () => EmitDoublingMultiplyHighHalf(context, round: true), SaturatingFlags.VectorSx); - } - - public static void Sqsub_S(ILEmitterCtx context) - { - EmitScalarSaturatingBinaryOpSx(context, SaturatingFlags.Sub); - } - - public static void Sqsub_V(ILEmitterCtx context) - { - EmitVectorSaturatingBinaryOpSx(context, SaturatingFlags.Sub); - } - - public static void Sqxtn_S(ILEmitterCtx context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.ScalarSxSx); - } - - public static void Sqxtn_V(ILEmitterCtx context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.VectorSxSx); - } - - public static void Sqxtun_S(ILEmitterCtx context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.ScalarSxZx); - } - - public static void Sqxtun_V(ILEmitterCtx context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.VectorSxZx); - } - - public static void Srhadd_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Type[] typesSav = new Type[] { IntTypesPerSizeLog2[op.Size] }; - Type[] typesSubAdd = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; - Type[] typesAvg = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdc_I4(op.Size == 0 ? sbyte.MinValue : short.MinValue); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAdd)); - - context.EmitLdvec(op.Rm); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesSubAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpSx(context, () => - { - context.Emit(OpCodes.Add); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Add); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr); - }); - } - } - - public static void Ssubl_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], - VectorIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmBinaryOpSx(context, () => context.Emit(OpCodes.Sub)); - } - } - - public static void Ssubw_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], - VectorIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRmBinaryOpSx(context, () => context.Emit(OpCodes.Sub)); - } - } - - public static void Sub_S(ILEmitterCtx context) - { - EmitScalarBinaryOpZx(context, () => context.Emit(OpCodes.Sub)); - } - - public static void Sub_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - EmitSse2Op(context, nameof(Sse2.Subtract)); - } - else - { - EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Sub)); - } - } - - public static void Subhn_V(ILEmitterCtx context) - { - EmitHighNarrow(context, () => context.Emit(OpCodes.Sub), round: false); - } - - public static void Suqadd_S(ILEmitterCtx context) - { - EmitScalarSaturatingBinaryOpSx(context, SaturatingFlags.Accumulate); - } - - public static void Suqadd_V(ILEmitterCtx context) - { - EmitVectorSaturatingBinaryOpSx(context, SaturatingFlags.Accumulate); - } - - public static void Uaba_V(ILEmitterCtx context) - { - EmitVectorTernaryOpZx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - - context.Emit(OpCodes.Add); - }); - } - - public static void Uabal_V(ILEmitterCtx context) - { - EmitVectorWidenRnRmTernaryOpZx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - - context.Emit(OpCodes.Add); - }); - } - - public static void Uabd_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; - Type[] typesAndOr = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesSav = new Type[] { typeof(long) }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); - - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmpSub)); - - context.EmitLdc_I8(-1L); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); - - context.EmitStvectmp(); // Cmp mask - context.EmitLdvectmp(); // Cmp mask - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); - - context.EmitLdvectmp(); // Cmp mask - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpZx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); - } - } - - public static void Uabdl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], - VectorUIntTypesPerSizeLog2[op.Size + 1] }; - Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2 [op.Size + 1], - VectorIntTypesPerSizeLog2 [op.Size + 1] }; - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAndOr = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesSav = new Type[] { typeof(long) }; - - string nameCvt = op.Size == 0 - ? nameof(Sse41.ConvertToVector128Int16) - : nameof(Sse41.ConvertToVector128Int32); - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitStvectmp2(); // Long Rm - context.EmitStvectmp(); // Long Rn - - context.EmitLdvectmp2(); // Long Rm - context.EmitLdvectmp(); // Long Rn - - context.EmitCall(typeof(Sse41).GetMethod(nameof(Sse41.Max), typesMax)); - - context.EmitLdvectmp2(); // Long Rm - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmpSub)); - - context.EmitLdc_I8(-1L); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); - - context.EmitStvectmp3(); // Cmp mask - context.EmitLdvectmp3(); // Cmp mask - - context.EmitLdvectmp(); // Long Rn - context.EmitLdvectmp2(); // Long Rm - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); - - context.EmitLdvectmp3(); // Cmp mask - - context.EmitLdvectmp2(); // Long Rm - context.EmitLdvectmp(); // Long Rn - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmBinaryOpZx(context, () => - { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); - } - } - - public static void Uadalp_V(ILEmitterCtx context) - { - EmitAddLongPairwise(context, signed: false, accumulate: true); - } - - public static void Uaddl_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], - VectorUIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmBinaryOpZx(context, () => context.Emit(OpCodes.Add)); - } - } - - public static void Uaddlp_V(ILEmitterCtx context) - { - EmitAddLongPairwise(context, signed: false, accumulate: false); - } - - public static void Uaddlv_V(ILEmitterCtx context) - { - EmitVectorLongAcrossVectorOpZx(context, () => context.Emit(OpCodes.Add)); - } - - public static void Uaddw_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], - VectorUIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRmBinaryOpZx(context, () => context.Emit(OpCodes.Add)); - } - } - - public static void Uhadd_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAndXorAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXorAdd)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXorAdd)); - - context.Emit(OpCodes.Ldc_I4_1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpZx(context, () => - { - context.Emit(OpCodes.Add); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr_Un); - }); - } - } - - public static void Uhsub_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Type[] typesAvgSub = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvgSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesAvgSub)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpZx(context, () => - { - context.Emit(OpCodes.Sub); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr_Un); - }); - } - } - - public static void Umax_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - Type[] types = new Type[] { typeof(ulong), typeof(ulong) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types); - - EmitVectorBinaryOpZx(context, () => context.EmitCall(mthdInfo)); - } - } - - public static void Umaxp_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(ulong), typeof(ulong) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types); - - EmitVectorPairwiseOpZx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Umaxv_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(ulong), typeof(ulong) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types); - - EmitVectorAcrossVectorOpZx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Umin_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesMin = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.Min), typesMin)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - Type[] types = new Type[] { typeof(ulong), typeof(ulong) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types); - - EmitVectorBinaryOpZx(context, () => context.EmitCall(mthdInfo)); - } - } - - public static void Uminp_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(ulong), typeof(ulong) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types); - - EmitVectorPairwiseOpZx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Uminv_V(ILEmitterCtx context) - { - Type[] types = new Type[] { typeof(ulong), typeof(ulong) }; - - MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types); - - EmitVectorAcrossVectorOpZx(context, () => context.EmitCall(mthdInfo)); - } - - public static void Umlal_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesMulAdd = new Type[] { VectorIntTypesPerSizeLog2 [op.Size + 1], - VectorIntTypesPerSizeLog2 [op.Size + 1] }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - string nameCvt = op.Size == 0 - ? nameof(Sse41.ConvertToVector128Int16) - : nameof(Sse41.ConvertToVector128Int32); - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.MultiplyLow), typesMulAdd)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmTernaryOpZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); - } - } - - public static void Umlal_Ve(ILEmitterCtx context) - { - EmitVectorWidenTernaryOpByElemZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); - } - - public static void Umlsl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesMulSub = new Type[] { VectorIntTypesPerSizeLog2 [op.Size + 1], - VectorIntTypesPerSizeLog2 [op.Size + 1] }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - string nameCvt = op.Size == 0 - ? nameof(Sse41.ConvertToVector128Int16) - : nameof(Sse41.ConvertToVector128Int32); - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.MultiplyLow), typesMulSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmTernaryOpZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); - } - } - - public static void Umlsl_Ve(ILEmitterCtx context) - { - EmitVectorWidenTernaryOpByElemZx(context, () => - { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); - } - - public static void Umull_V(ILEmitterCtx context) - { - EmitVectorWidenRnRmBinaryOpZx(context, () => context.Emit(OpCodes.Mul)); - } - - public static void Umull_Ve(ILEmitterCtx context) - { - EmitVectorWidenBinaryOpByElemZx(context, () => context.Emit(OpCodes.Mul)); - } - - public static void Uqadd_S(ILEmitterCtx context) - { - EmitScalarSaturatingBinaryOpZx(context, SaturatingFlags.Add); - } - - public static void Uqadd_V(ILEmitterCtx context) - { - EmitVectorSaturatingBinaryOpZx(context, SaturatingFlags.Add); - } - - public static void Uqsub_S(ILEmitterCtx context) - { - EmitScalarSaturatingBinaryOpZx(context, SaturatingFlags.Sub); - } - - public static void Uqsub_V(ILEmitterCtx context) - { - EmitVectorSaturatingBinaryOpZx(context, SaturatingFlags.Sub); - } - - public static void Uqxtn_S(ILEmitterCtx context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.ScalarZxZx); - } - - public static void Uqxtn_V(ILEmitterCtx context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.VectorZxZx); - } - - public static void Urhadd_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Type[] typesAvg = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpZx(context, () => - { - context.Emit(OpCodes.Add); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Add); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Shr_Un); - }); - } - } - - public static void Usqadd_S(ILEmitterCtx context) - { - EmitScalarSaturatingBinaryOpZx(context, SaturatingFlags.Accumulate); - } - - public static void Usqadd_V(ILEmitterCtx context) - { - EmitVectorSaturatingBinaryOpZx(context, SaturatingFlags.Accumulate); - } - - public static void Usubl_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesSub = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], - VectorUIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRnRmBinaryOpZx(context, () => context.Emit(OpCodes.Sub)); - } - } - - public static void Usubw_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesSub = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], - VectorUIntTypesPerSizeLog2[op.Size + 1] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorWidenRmBinaryOpZx(context, () => context.Emit(OpCodes.Sub)); - } - } - - private static void EmitAbs(ILEmitterCtx context) - { - ILLabel lblTrue = new ILLabel(); - - context.Emit(OpCodes.Dup); - context.Emit(OpCodes.Ldc_I4_0); - context.Emit(OpCodes.Bge_S, lblTrue); - - context.Emit(OpCodes.Neg); - - context.MarkLabel(lblTrue); - } - - private static void EmitAddLongPairwise(ILEmitterCtx context, bool signed, bool accumulate) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int words = op.GetBitsCount() >> 4; - int pairs = words >> op.Size; - - for (int index = 0; index < pairs; index++) - { - int idx = index << 1; - - EmitVectorExtract(context, op.Rn, idx, op.Size, signed); - EmitVectorExtract(context, op.Rn, idx + 1, op.Size, signed); - - context.Emit(OpCodes.Add); - - if (accumulate) - { - EmitVectorExtract(context, op.Rd, index, op.Size + 1, signed); - - context.Emit(OpCodes.Add); - } - - EmitVectorInsertTmp(context, index, op.Size + 1); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitDoublingMultiplyHighHalf(ILEmitterCtx context, bool round) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int eSize = 8 << op.Size; - - context.Emit(OpCodes.Mul); - - if (!round) - { - context.EmitAsr(eSize - 1); - } - else - { - long roundConst = 1L << (eSize - 1); - - ILLabel lblTrue = new ILLabel(); - - context.EmitLsl(1); - - context.EmitLdc_I8(roundConst); - - context.Emit(OpCodes.Add); - - context.EmitAsr(eSize); - - context.Emit(OpCodes.Dup); - context.EmitLdc_I8((long)int.MinValue); - context.Emit(OpCodes.Bne_Un_S, lblTrue); - - context.Emit(OpCodes.Neg); - - context.MarkLabel(lblTrue); - } - } - - private static void EmitHighNarrow(ILEmitterCtx context, Action emit, bool round) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int elems = 8 >> op.Size; - - int eSize = 8 << op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - long roundConst = 1L << (eSize - 1); - - if (part != 0) - { - context.EmitLdvec(op.Rd); - context.EmitStvectmp(); - } - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size + 1); - EmitVectorExtractZx(context, op.Rm, index, op.Size + 1); - - emit(); - - if (round) - { - context.EmitLdc_I8(roundConst); - - context.Emit(OpCodes.Add); - } - - context.EmitLsr(eSize); - - EmitVectorInsertTmp(context, part + index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (part == 0) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitSse41Frint(ILEmitterCtx context, RoundMode roundMode, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - if (scalar) - { - Type[] typesRnd = op.Size == 0 - ? new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) } - : new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse41).GetMethod(GetScalarSse41NameRnd(roundMode), typesRnd)); - - context.EmitStvec(op.Rd); - } - else - { - int sizeF = op.Size & 1; - - Type[] typesRnd = sizeF == 0 - ? new Type[] { typeof(Vector128<float>) } - : new Type[] { typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse41).GetMethod(GetVectorSse41NameRnd(roundMode), typesRnd)); - - context.EmitStvec(op.Rd); - - if (sizeF == 0 && op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - private static void EmitSse41Mul_AddSub(ILEmitterCtx context, string nameAddSub = null) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (nameAddSub != null) - { - context.EmitLdvec(op.Rd); - } - - if (op.Size == 0) - { - Type[] typesBle = new Type[] { typeof(Vector128<sbyte>), typeof(Vector128<sbyte>), typeof(Vector128<sbyte>) }; - Type[] typesMul = new Type[] { typeof(Vector128<short>), typeof(Vector128<short>) }; - Type[] typesShs = new Type[] { typeof(Vector128<short>), typeof(byte) }; - Type[] typesSav = new Type[] { typeof(int) }; - - context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyLow), typesMul)); - - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyLow), typesMul)); - - context.EmitLdc_I4(0x00FF00FF); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), typesBle)); - } - else if (op.Size == 1) - { - Type[] typesMul = new Type[] { typeof(Vector128<short>), typeof(Vector128<short>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyLow), typesMul)); - } - else /* if (op.Size == 2) */ - { - Type[] typesMul = new Type[] { typeof(Vector128<int>), typeof(Vector128<int>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse41).GetMethod(nameof(Sse41.MultiplyLow), typesMul)); - } - - if (nameAddSub != null) - { - Type[] typesAddSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - context.EmitCall(typeof(Sse2).GetMethod(nameAddSub, typesAddSub)); - } - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdCmp.cs b/ChocolArm64/Instructions/InstEmitSimdCmp.cs deleted file mode 100644 index b2925006..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdCmp.cs +++ /dev/null @@ -1,862 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -using static ChocolArm64.Instructions.InstEmitAluHelper; -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Cmeq_S(ILEmitterCtx context) - { - EmitCmpOp(context, OpCodes.Beq_S, scalar: true); - } - - public static void Cmeq_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rn); - - if (op is OpCodeSimdReg64 binOp) - { - context.EmitLdvec(binOp.Rm); - } - else - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - } - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareEqual), typesCmp)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitCmpOp(context, OpCodes.Beq_S, scalar: false); - } - } - - public static void Cmge_S(ILEmitterCtx context) - { - EmitCmpOp(context, OpCodes.Bge_S, scalar: true); - } - - public static void Cmge_V(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesAnt = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesSav = new Type[] { typeof(long) }; - - Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); - - if (op is OpCodeSimdReg64 binOp) - { - context.EmitLdvec(binOp.Rm); - } - else - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - } - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); - - context.EmitLdc_I8(-1L); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitCmpOp(context, OpCodes.Bge_S, scalar: false); - } - } - - public static void Cmgt_S(ILEmitterCtx context) - { - EmitCmpOp(context, OpCodes.Bgt_S, scalar: true); - } - - public static void Cmgt_V(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); - - context.EmitLdvec(op.Rn); - - if (op is OpCodeSimdReg64 binOp) - { - context.EmitLdvec(binOp.Rm); - } - else - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - } - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitCmpOp(context, OpCodes.Bgt_S, scalar: false); - } - } - - public static void Cmhi_S(ILEmitterCtx context) - { - EmitCmpOp(context, OpCodes.Bgt_Un_S, scalar: true); - } - - public static void Cmhi_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 3) - { - Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; - Type[] typesAnt = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesSav = new Type[] { typeof(long) }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); - - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmp)); - - context.EmitLdc_I8(-1L); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitCmpOp(context, OpCodes.Bgt_Un_S, scalar: false); - } - } - - public static void Cmhs_S(ILEmitterCtx context) - { - EmitCmpOp(context, OpCodes.Bge_Un_S, scalar: true); - } - - public static void Cmhs_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 3) - { - Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; - - Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmp)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitCmpOp(context, OpCodes.Bge_Un_S, scalar: false); - } - } - - public static void Cmle_S(ILEmitterCtx context) - { - EmitCmpOp(context, OpCodes.Ble_S, scalar: true); - } - - public static void Cmle_V(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - Type[] typesAnt = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesSav = new Type[] { typeof(long) }; - - Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); - - context.EmitLdvec(op.Rn); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); - - context.EmitLdc_I8(-1L); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitCmpOp(context, OpCodes.Ble_S, scalar: false); - } - } - - public static void Cmlt_S(ILEmitterCtx context) - { - EmitCmpOp(context, OpCodes.Blt_S, scalar: true); - } - - public static void Cmlt_V(ILEmitterCtx context) - { - if (Optimizations.UseSse42) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitCmpOp(context, OpCodes.Blt_S, scalar: false); - } - } - - public static void Cmtst_S(ILEmitterCtx context) - { - EmitCmtstOp(context, scalar: true); - } - - public static void Cmtst_V(ILEmitterCtx context) - { - EmitCmtstOp(context, scalar: false); - } - - public static void Fccmp_S(ILEmitterCtx context) - { - OpCodeSimdFcond64 op = (OpCodeSimdFcond64)context.CurrOp; - - ILLabel lblTrue = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitCondBranch(lblTrue, op.Cond); - - context.EmitLdc_I4(op.Nzcv); - EmitSetNzcv(context); - - context.Emit(OpCodes.Br, lblEnd); - - context.MarkLabel(lblTrue); - - EmitFcmpOrFcmpe(context, signalNaNs: false); - - context.MarkLabel(lblEnd); - } - - public static void Fccmpe_S(ILEmitterCtx context) - { - OpCodeSimdFcond64 op = (OpCodeSimdFcond64)context.CurrOp; - - ILLabel lblTrue = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitCondBranch(lblTrue, op.Cond); - - context.EmitLdc_I4(op.Nzcv); - EmitSetNzcv(context); - - context.Emit(OpCodes.Br, lblEnd); - - context.MarkLabel(lblTrue); - - EmitFcmpOrFcmpe(context, signalNaNs: true); - - context.MarkLabel(lblEnd); - } - - public static void Fcmeq_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareEqualScalar), scalar: true); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: true); - } - } - - public static void Fcmeq_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareEqual), scalar: false); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: false); - } - } - - public static void Fcmge_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqualScalar), scalar: true); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true); - } - } - - public static void Fcmge_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqual), scalar: false); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false); - } - } - - public static void Fcmgt_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanScalar), scalar: true); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true); - } - } - - public static void Fcmgt_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThan), scalar: false); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false); - } - } - - public static void Fcmle_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqualScalar), scalar: true, isLeOrLt: true); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: true); - } - } - - public static void Fcmle_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqual), scalar: false, isLeOrLt: true); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: false); - } - } - - public static void Fcmlt_S(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanScalar), scalar: true, isLeOrLt: true); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: true); - } - } - - public static void Fcmlt_V(ILEmitterCtx context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThan), scalar: false, isLeOrLt: true); - } - else - { - EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: false); - } - } - - public static void Fcmp_S(ILEmitterCtx context) - { - EmitFcmpOrFcmpe(context, signalNaNs: false); - } - - public static void Fcmpe_S(ILEmitterCtx context) - { - EmitFcmpOrFcmpe(context, signalNaNs: true); - } - - private static void EmitFcmpOrFcmpe(ILEmitterCtx context, bool signalNaNs) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - bool cmpWithZero = !(op is OpCodeSimdFcond64) ? op.Bit3 : false; - - if (Optimizations.FastFP && Optimizations.UseSse2) - { - if (op.Size == 0) - { - Type[] typesCmp = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - ILLabel lblNaN = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitLdvec(op.Rn); - - if (cmpWithZero) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - } - else - { - context.EmitLdvec(op.Rm); - } - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), typesCmp)); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp)); - - context.Emit(OpCodes.Brtrue_S, lblNaN); - - context.Emit(OpCodes.Ldc_I4_0); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), typesCmp)); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp)); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), typesCmp)); - - context.EmitStflg((int)PState.NBit); - context.EmitStflg((int)PState.ZBit); - context.EmitStflg((int)PState.CBit); - context.EmitStflg((int)PState.VBit); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblNaN); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Ldc_I4_0); - context.Emit(OpCodes.Ldc_I4_0); - - context.EmitStflg((int)PState.NBit); - context.EmitStflg((int)PState.ZBit); - context.EmitStflg((int)PState.CBit); - context.EmitStflg((int)PState.VBit); - - context.MarkLabel(lblEnd); - } - else /* if (op.Size == 1) */ - { - Type[] typesCmp = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - ILLabel lblNaN = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitLdvec(op.Rn); - - if (cmpWithZero) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - } - else - { - context.EmitLdvec(op.Rm); - } - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrderedScalar), typesCmp)); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp)); - - context.Emit(OpCodes.Brtrue_S, lblNaN); - - context.Emit(OpCodes.Ldc_I4_0); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqualOrderedScalar), typesCmp)); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp)); - - context.EmitLdvec(op.Rn); - context.EmitLdvectmp(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrderedScalar), typesCmp)); - - context.EmitStflg((int)PState.NBit); - context.EmitStflg((int)PState.ZBit); - context.EmitStflg((int)PState.CBit); - context.EmitStflg((int)PState.VBit); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblNaN); - - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Ldc_I4_1); - context.Emit(OpCodes.Ldc_I4_0); - context.Emit(OpCodes.Ldc_I4_0); - - context.EmitStflg((int)PState.NBit); - context.EmitStflg((int)PState.ZBit); - context.EmitStflg((int)PState.CBit); - context.EmitStflg((int)PState.VBit); - - context.MarkLabel(lblEnd); - } - } - else - { - EmitVectorExtractF(context, op.Rn, 0, op.Size); - - if (cmpWithZero) - { - if (op.Size == 0) - { - context.EmitLdc_R4(0f); - } - else /* if (op.Size == 1) */ - { - context.EmitLdc_R8(0d); - } - } - else - { - EmitVectorExtractF(context, op.Rm, 0, op.Size); - } - - context.EmitLdc_I4(!signalNaNs ? 0 : 1); - - EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare)); - - EmitSetNzcv(context); - } - } - - private static void EmitCmpOp(ILEmitterCtx context, OpCode ilOp, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> op.Size : 1; - - ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size)); - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractSx(context, op.Rn, index, op.Size); - - if (op is OpCodeSimdReg64 binOp) - { - EmitVectorExtractSx(context, binOp.Rm, index, op.Size); - } - else - { - context.EmitLdc_I8(0L); - } - - ILLabel lblTrue = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(ilOp, lblTrue); - - EmitVectorInsert(context, op.Rd, index, op.Size, 0); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblTrue); - - EmitVectorInsert(context, op.Rd, index, op.Size, (long)szMask); - - context.MarkLabel(lblEnd); - } - - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitCmtstOp(ILEmitterCtx context, bool scalar) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> op.Size : 1; - - ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size)); - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - EmitVectorExtractZx(context, op.Rm, index, op.Size); - - ILLabel lblTrue = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.Emit(OpCodes.And); - - context.EmitLdc_I8(0L); - - context.Emit(OpCodes.Bne_Un_S, lblTrue); - - EmitVectorInsert(context, op.Rd, index, op.Size, 0); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblTrue); - - EmitVectorInsert(context, op.Rd, index, op.Size, (long)szMask); - - context.MarkLabel(lblEnd); - } - - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitCmpOpF(ILEmitterCtx context, string name, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> sizeF + 2 : 1; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractF(context, op.Rn, index, sizeF); - - if (op is OpCodeSimdReg64 binOp) - { - EmitVectorExtractF(context, binOp.Rm, index, sizeF); - } - else - { - if (sizeF == 0) - { - context.EmitLdc_R4(0f); - } - else /* if (sizeF == 1) */ - { - context.EmitLdc_R8(0d); - } - } - - EmitSoftFloatCall(context, name); - - EmitVectorInsertF(context, op.Rd, index, sizeF); - } - - if (!scalar) - { - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - if (sizeF == 0) - { - EmitVectorZero32_128(context, op.Rd); - } - else /* if (sizeF == 1) */ - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - private static void EmitCmpSseOrSse2OpF(ILEmitterCtx context, string name, bool scalar, bool isLeOrLt = false) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] types = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - if (!isLeOrLt) - { - context.EmitLdvec(op.Rn); - } - - if (op is OpCodeSimdReg64 binOp) - { - context.EmitLdvec(binOp.Rm); - } - else - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - } - - if (isLeOrLt) - { - context.EmitLdvec(op.Rn); - } - - context.EmitCall(typeof(Sse).GetMethod(name, types)); - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZero32_128(context, op.Rd); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] types = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - if (!isLeOrLt) - { - context.EmitLdvec(op.Rn); - } - - if (op is OpCodeSimdReg64 binOp) - { - context.EmitLdvec(binOp.Rm); - } - else - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - } - - if (isLeOrLt) - { - context.EmitLdvec(op.Rn); - } - - context.EmitCall(typeof(Sse2).GetMethod(name, types)); - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdCrypto.cs b/ChocolArm64/Instructions/InstEmitSimdCrypto.cs deleted file mode 100644 index 33c81aab..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdCrypto.cs +++ /dev/null @@ -1,54 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.Translation; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Aesd_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - SoftFallback.EmitCall(context, nameof(SoftFallback.Decrypt)); - - context.EmitStvec(op.Rd); - } - - public static void Aese_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - SoftFallback.EmitCall(context, nameof(SoftFallback.Encrypt)); - - context.EmitStvec(op.Rd); - } - - public static void Aesimc_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdvec(op.Rn); - - SoftFallback.EmitCall(context, nameof(SoftFallback.InverseMixColumns)); - - context.EmitStvec(op.Rd); - } - - public static void Aesmc_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdvec(op.Rn); - - SoftFallback.EmitCall(context, nameof(SoftFallback.MixColumns)); - - context.EmitStvec(op.Rd); - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdCvt.cs b/ChocolArm64/Instructions/InstEmitSimdCvt.cs deleted file mode 100644 index 2b3deb98..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdCvt.cs +++ /dev/null @@ -1,1382 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Fcvt_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - if (op.Size == 0 && op.Opc == 1) // Single -> Double. - { - if (Optimizations.UseSse2) - { - Type[] typesCvt = new Type[] { typeof(Vector128<double>), typeof(Vector128<float>) }; - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), typesCvt)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorExtractF(context, op.Rn, 0, 0); - - EmitFloatCast(context, 1); - - EmitScalarSetF(context, op.Rd, 1); - } - } - else if (op.Size == 1 && op.Opc == 0) // Double -> Single. - { - if (Optimizations.UseSse2) - { - Type[] typesCvt = new Type[] { typeof(Vector128<float>), typeof(Vector128<double>) }; - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), typesCvt)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorExtractF(context, op.Rn, 0, 1); - - EmitFloatCast(context, 0); - - EmitScalarSetF(context, op.Rd, 0); - } - } - else if (op.Size == 0 && op.Opc == 3) // Single -> Half. - { - EmitVectorExtractF(context, op.Rn, 0, 0); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCall(typeof(SoftFloat32_16), nameof(SoftFloat32_16.FPConvert)); - - context.Emit(OpCodes.Conv_U8); - EmitScalarSet(context, op.Rd, 1); - } - else if (op.Size == 3 && op.Opc == 0) // Half -> Single. - { - EmitVectorExtractZx(context, op.Rn, 0, 1); - context.Emit(OpCodes.Conv_U2); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCall(typeof(SoftFloat16_32), nameof(SoftFloat16_32.FPConvert)); - - EmitScalarSetF(context, op.Rd, 0); - } - else if (op.Size == 1 && op.Opc == 3) // Double -> Half. - { - throw new NotImplementedException("Double-precision to half-precision."); - } - else if (op.Size == 3 && op.Opc == 1) // Double -> Half. - { - throw new NotImplementedException("Half-precision to double-precision."); - } - else // Invalid encoding. - { - throw new InvalidOperationException($"type == {op.Size} && opc == {op.Opc}"); - } - } - - public static void Fcvtas_Gp(ILEmitterCtx context) - { - EmitFcvt_s_Gp(context, () => EmitRoundMathCall(context, MidpointRounding.AwayFromZero)); - } - - public static void Fcvtau_Gp(ILEmitterCtx context) - { - EmitFcvt_u_Gp(context, () => EmitRoundMathCall(context, MidpointRounding.AwayFromZero)); - } - - public static void Fcvtl_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 1) - { - Type[] typesCvt = new Type[] { typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveHighToLow))); - } - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Double), typesCvt)); - - context.EmitStvec(op.Rd); - } - else - { - int elems = 4 >> sizeF; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - for (int index = 0; index < elems; index++) - { - if (sizeF == 0) - { - EmitVectorExtractZx(context, op.Rn, part + index, 1); - context.Emit(OpCodes.Conv_U2); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCall(typeof(SoftFloat16_32), nameof(SoftFloat16_32.FPConvert)); - } - else /* if (sizeF == 1) */ - { - EmitVectorExtractF(context, op.Rn, part + index, 0); - - context.Emit(OpCodes.Conv_R8); - } - - EmitVectorInsertTmpF(context, index, sizeF); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - } - } - - public static void Fcvtms_Gp(ILEmitterCtx context) - { - EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor))); - } - - public static void Fcvtmu_Gp(ILEmitterCtx context) - { - EmitFcvt_u_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor))); - } - - public static void Fcvtn_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 1) - { - Type[] typesCvt = new Type[] { typeof(Vector128<double>) }; - - string nameMov = op.RegisterSize == RegisterSize.Simd128 - ? nameof(Sse.MoveLowToHigh) - : nameof(Sse.MoveHighToLow); - - context.EmitLdvec(op.Rd); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - - context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); - context.Emit(OpCodes.Dup); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - - context.EmitCall(typeof(Sse).GetMethod(nameMov)); - - context.EmitStvec(op.Rd); - } - else - { - int elems = 4 >> sizeF; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - if (part != 0) - { - context.EmitLdvec(op.Rd); - context.EmitStvectmp(); - } - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractF(context, op.Rn, index, sizeF); - - if (sizeF == 0) - { - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCall(typeof(SoftFloat32_16), nameof(SoftFloat32_16.FPConvert)); - - context.Emit(OpCodes.Conv_U8); - EmitVectorInsertTmp(context, part + index, 1); - } - else /* if (sizeF == 1) */ - { - context.Emit(OpCodes.Conv_R4); - - EmitVectorInsertTmpF(context, part + index, 0); - } - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (part == 0) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - public static void Fcvtns_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, scalar: true); - } - else - { - EmitFcvtn(context, signed: true, scalar: true); - } - } - - public static void Fcvtns_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, scalar: false); - } - else - { - EmitFcvtn(context, signed: true, scalar: false); - } - } - - public static void Fcvtnu_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Unsigned(context, RoundMode.ToNearest, scalar: true); - } - else - { - EmitFcvtn(context, signed: false, scalar: true); - } - } - - public static void Fcvtnu_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Unsigned(context, RoundMode.ToNearest, scalar: false); - } - else - { - EmitFcvtn(context, signed: false, scalar: false); - } - } - - public static void Fcvtps_Gp(ILEmitterCtx context) - { - EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling))); - } - - public static void Fcvtpu_Gp(ILEmitterCtx context) - { - EmitFcvt_u_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling))); - } - - public static void Fcvtzs_Gp(ILEmitterCtx context) - { - EmitFcvt_s_Gp(context, () => { }); - } - - public static void Fcvtzs_Gp_Fixed(ILEmitterCtx context) - { - EmitFcvtzs_Gp_Fixed(context); - } - - public static void Fcvtzs_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, scalar: true); - } - else - { - EmitFcvtz(context, signed: true, scalar: true); - } - } - - public static void Fcvtzs_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: true, scalar: false); - } - } - - public static void Fcvtzs_V_Fixed(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: true, scalar: false); - } - } - - public static void Fcvtzu_Gp(ILEmitterCtx context) - { - EmitFcvt_u_Gp(context, () => { }); - } - - public static void Fcvtzu_Gp_Fixed(ILEmitterCtx context) - { - EmitFcvtzu_Gp_Fixed(context); - } - - public static void Fcvtzu_S(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Unsigned(context, RoundMode.TowardsZero, scalar: true); - } - else - { - EmitFcvtz(context, signed: false, scalar: true); - } - } - - public static void Fcvtzu_V(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Unsigned(context, RoundMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: false, scalar: false); - } - } - - public static void Fcvtzu_V_Fixed(ILEmitterCtx context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Unsigned(context, RoundMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: false, scalar: false); - } - } - - public static void Scvtf_Gp(ILEmitterCtx context) - { - OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_I4); - } - - EmitFloatCast(context, op.Size); - - EmitScalarSetF(context, op.Rd, op.Size); - } - - public static void Scvtf_Gp_Fixed(ILEmitterCtx context) - { - OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_I4); - } - - EmitFloatCast(context, op.Size); - - EmitI2fFBitsMul(context, op.Size, op.FBits); - - EmitScalarSetF(context, op.Rd, op.Size); - } - - public static void Scvtf_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 0) - { - EmitSse2cvtF_Signed(context, scalar: true); - } - else - { - EmitVectorExtractSx(context, op.Rn, 0, sizeF + 2); - - EmitFloatCast(context, sizeF); - - EmitScalarSetF(context, op.Rd, sizeF); - } - } - - public static void Scvtf_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 0) - { - EmitSse2cvtF_Signed(context, scalar: false); - } - else - { - EmitVectorCvtf(context, signed: true); - } - } - - public static void Scvtf_V_Fixed(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - // sizeF == ((OpCodeSimdShImm64)op).Size - 2 - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 0) - { - EmitSse2cvtF_Signed(context, scalar: false); - } - else - { - EmitVectorCvtf(context, signed: true); - } - } - - public static void Ucvtf_Gp(ILEmitterCtx context) - { - OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U4); - } - - context.Emit(OpCodes.Conv_R_Un); - - EmitFloatCast(context, op.Size); - - EmitScalarSetF(context, op.Rd, op.Size); - } - - public static void Ucvtf_Gp_Fixed(ILEmitterCtx context) - { - OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U4); - } - - context.Emit(OpCodes.Conv_R_Un); - - EmitFloatCast(context, op.Size); - - EmitI2fFBitsMul(context, op.Size, op.FBits); - - EmitScalarSetF(context, op.Rd, op.Size); - } - - public static void Ucvtf_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 0) - { - EmitSse2cvtF_Unsigned(context, scalar: true); - } - else - { - EmitVectorExtractZx(context, op.Rn, 0, sizeF + 2); - - context.Emit(OpCodes.Conv_R_Un); - - EmitFloatCast(context, sizeF); - - EmitScalarSetF(context, op.Rd, sizeF); - } - } - - public static void Ucvtf_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 0) - { - EmitSse2cvtF_Unsigned(context, scalar: false); - } - else - { - EmitVectorCvtf(context, signed: false); - } - } - - public static void Ucvtf_V_Fixed(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - // sizeF == ((OpCodeSimdShImm64)op).Size - 2 - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 0) - { - EmitSse2cvtF_Unsigned(context, scalar: false); - } - else - { - EmitVectorCvtf(context, signed: false); - } - } - - private static void EmitFcvtn(ILEmitterCtx context, bool signed, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> sizeI : 1; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractF(context, op.Rn, index, sizeF); - - EmitRoundMathCall(context, MidpointRounding.ToEven); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF32ToS32) - : nameof(VectorHelper.SatF32ToU32)); - - context.Emit(OpCodes.Conv_U8); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF64ToS64) - : nameof(VectorHelper.SatF64ToU64)); - } - - if (scalar) - { - EmitVectorZeroAll(context, op.Rd); - } - - EmitVectorInsert(context, op.Rd, index, sizeI); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitFcvtz(ILEmitterCtx context, bool signed, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - int fBits = GetFBits(context); - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> sizeI : 1; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractF(context, op.Rn, index, sizeF); - - EmitF2iFBitsMul(context, sizeF, fBits); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF32ToS32) - : nameof(VectorHelper.SatF32ToU32)); - - context.Emit(OpCodes.Conv_U8); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF64ToS64) - : nameof(VectorHelper.SatF64ToU64)); - } - - if (scalar) - { - EmitVectorZeroAll(context, op.Rd); - } - - EmitVectorInsert(context, op.Rd, index, sizeI); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitFcvt_s_Gp(ILEmitterCtx context, Action emit) - { - EmitFcvt___Gp(context, emit, true); - } - - private static void EmitFcvt_u_Gp(ILEmitterCtx context, Action emit) - { - EmitFcvt___Gp(context, emit, false); - } - - private static void EmitFcvt___Gp(ILEmitterCtx context, Action emit, bool signed) - { - OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; - - EmitVectorExtractF(context, op.Rn, 0, op.Size); - - emit(); - - if (signed) - { - EmitScalarFcvts(context, op.Size, 0); - } - else - { - EmitScalarFcvtu(context, op.Size, 0); - } - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitStintzr(op.Rd); - } - - private static void EmitFcvtzs_Gp_Fixed(ILEmitterCtx context) - { - EmitFcvtz__Gp_Fixed(context, true); - } - - private static void EmitFcvtzu_Gp_Fixed(ILEmitterCtx context) - { - EmitFcvtz__Gp_Fixed(context, false); - } - - private static void EmitFcvtz__Gp_Fixed(ILEmitterCtx context, bool signed) - { - OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; - - EmitVectorExtractF(context, op.Rn, 0, op.Size); - - if (signed) - { - EmitScalarFcvts(context, op.Size, op.FBits); - } - else - { - EmitScalarFcvtu(context, op.Size, op.FBits); - } - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitStintzr(op.Rd); - } - - private static void EmitVectorCvtf(ILEmitterCtx context, bool signed) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - int fBits = GetFBits(context); - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> sizeI; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, sizeI, signed); - - if (!signed) - { - context.Emit(OpCodes.Conv_R_Un); - } - - EmitFloatCast(context, sizeF); - - EmitI2fFBitsMul(context, sizeF, fBits); - - EmitVectorInsertF(context, op.Rd, index, sizeF); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static int GetFBits(ILEmitterCtx context) - { - if (context.CurrOp is OpCodeSimdShImm64 op) - { - return GetImmShr(op); - } - - return 0; - } - - private static void EmitFloatCast(ILEmitterCtx context, int size) - { - if (size == 0) - { - context.Emit(OpCodes.Conv_R4); - } - else if (size == 1) - { - context.Emit(OpCodes.Conv_R8); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - - private static void EmitScalarFcvts(ILEmitterCtx context, int size, int fBits) - { - if (size < 0 || size > 1) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - EmitF2iFBitsMul(context, size, fBits); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - if (size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToS32)); - } - else /* if (size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToS32)); - } - } - else - { - if (size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToS64)); - } - else /* if (size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToS64)); - } - } - } - - private static void EmitScalarFcvtu(ILEmitterCtx context, int size, int fBits) - { - if (size < 0 || size > 1) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - EmitF2iFBitsMul(context, size, fBits); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - if (size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToU32)); - } - else /* if (size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToU32)); - } - } - else - { - if (size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToU64)); - } - else /* if (size == 1) */ - { - VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToU64)); - } - } - } - - private static void EmitF2iFBitsMul(ILEmitterCtx context, int size, int fBits) - { - if (fBits != 0) - { - if (size == 0) - { - context.EmitLdc_R4(MathF.Pow(2f, fBits)); - } - else if (size == 1) - { - context.EmitLdc_R8(Math.Pow(2d, fBits)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - context.Emit(OpCodes.Mul); - } - } - - private static void EmitI2fFBitsMul(ILEmitterCtx context, int size, int fBits) - { - if (fBits != 0) - { - if (size == 0) - { - context.EmitLdc_R4(1f / MathF.Pow(2f, fBits)); - } - else if (size == 1) - { - context.EmitLdc_R8(1d / Math.Pow(2d, fBits)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - context.Emit(OpCodes.Mul); - } - } - - private static void EmitSse41Fcvt_Signed(ILEmitterCtx context, RoundMode roundMode, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - // sizeF == ((OpCodeSimdShImm64)op).Size - 2 - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] types = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - Type[] typesRndCvt = new Type[] { typeof(Vector128<float>) }; - Type[] typesSav = new Type[] { typeof(int) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), types)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); - - if (op is OpCodeSimdShImm64 fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 + fBits * 0x800000; - - context.EmitLdc_I4(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), types)); - } - - context.EmitCall(typeof(Sse41).GetMethod(GetVectorSse41NameRnd(roundMode), typesRndCvt)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); - - context.EmitLdvectmp(); - - context.EmitLdc_I4(0x4F000000); // 2.14748365E9f (2147483648) - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), types)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Xor), types)); - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZero32_128(context, op.Rd); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] types = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - Type[] typesRndCvt = new Type[] { typeof(Vector128<double>) }; - Type[] typesSv = new Type[] { typeof(long), typeof(long) }; - Type[] typesSav = new Type[] { typeof(long) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), types)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); - - if (op is OpCodeSimdShImm64 fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) - long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; - - context.EmitLdc_I8(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), types)); - } - - context.EmitCall(typeof(Sse41).GetMethod(GetVectorSse41NameRnd(roundMode), typesRndCvt)); - - context.EmitStvectmp(); - - if (!scalar) - { - context.EmitLdvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); - } - else - { - context.EmitLdc_I8(0L); - } - - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); - - context.EmitLdvectmp(); - - context.EmitLdc_I8(0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types)); - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - private static void EmitSse41Fcvt_Unsigned(ILEmitterCtx context, RoundMode roundMode, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - // sizeF == ((OpCodeSimdShImm64)op).Size - 2 - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Type[] types = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - Type[] typesAdd = new Type[] { typeof(Vector128<int>), typeof(Vector128<int>) }; - Type[] typesRndCvt = new Type[] { typeof(Vector128<float>) }; - Type[] typesSav = new Type[] { typeof(int) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), types)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); - - if (op is OpCodeSimdShImm64 fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 + fBits * 0x800000; - - context.EmitLdc_I4(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), types)); - } - - context.EmitCall(typeof(Sse41).GetMethod(GetVectorSse41NameRnd(roundMode), typesRndCvt)); - - context.Emit(OpCodes.Dup); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), types)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); - - context.EmitLdvectmp(); - - context.EmitLdc_I4(0x4F000000); // 2.14748365E9f (2147483648) - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvectmp2(); - context.EmitLdvectmp2(); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), types)); - - context.Emit(OpCodes.Dup); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), types)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); - - context.EmitLdvectmp(); - context.EmitLdvectmp2(); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), types)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Xor), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZero32_128(context, op.Rd); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] types = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - Type[] typesAdd = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesRndCvt = new Type[] { typeof(Vector128<double>) }; - Type[] typesSv = new Type[] { typeof(long), typeof(long) }; - Type[] typesSav = new Type[] { typeof(long) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), types)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); - - if (op is OpCodeSimdShImm64 fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) - long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; - - context.EmitLdc_I8(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), types)); - } - - context.EmitCall(typeof(Sse41).GetMethod(GetVectorSse41NameRnd(roundMode), typesRndCvt)); - - context.Emit(OpCodes.Dup); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); - - context.EmitStvectmp(); - - if (!scalar) - { - context.EmitLdvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); - } - else - { - context.EmitLdc_I8(0L); - } - - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); - - context.EmitLdvectmp(); - - context.EmitLdc_I8(0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvectmp2(); - context.EmitLdvectmp2(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), types)); - - context.Emit(OpCodes.Dup); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); - - context.EmitStvectmp(); - - if (!scalar) - { - context.EmitLdvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); - } - else - { - context.EmitLdc_I8(0L); - } - - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); - - context.EmitLdvectmp(); - context.EmitLdvectmp2(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - private static void EmitSse2cvtF_Signed(ILEmitterCtx context, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesMul = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - Type[] typesCvt = new Type[] { typeof(Vector128<int>) }; - Type[] typesSav = new Type[] { typeof(int) }; - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); - - if (op is OpCodeSimdShImm64 fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == 1f / MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 - fBits * 0x800000; - - context.EmitLdc_I4(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMul)); - } - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZero32_128(context, op.Rd); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitSse2cvtF_Unsigned(ILEmitterCtx context, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesMulAdd = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - Type[] typesSrlSll = new Type[] { typeof(Vector128<int>), typeof(byte) }; - Type[] typesCvt = new Type[] { typeof(Vector128<int>) }; - Type[] typesSav = new Type[] { typeof(int) }; - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(16); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrlSll)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); - - context.EmitLdc_I4(0x47800000); // 65536.0f (1 << 16) - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(16); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSrlSll)); - - context.EmitLdc_I4(16); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrlSll)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Add), typesMulAdd)); - - if (op is OpCodeSimdShImm64 fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == 1f / MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 - fBits * 0x800000; - - context.EmitLdc_I4(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); - } - - context.EmitStvec(op.Rd); - - if (scalar) - { - EmitVectorZero32_128(context, op.Rd); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static string GetScalarSse41NameRnd(RoundMode roundMode) - { - switch (roundMode) - { - case RoundMode.ToNearest: - return nameof(Sse41.RoundToNearestIntegerScalar); // even - - case RoundMode.TowardsPlusInfinity: - return nameof(Sse41.RoundToPositiveInfinityScalar); - - case RoundMode.TowardsMinusInfinity: - return nameof(Sse41.RoundToNegativeInfinityScalar); - - default: /* case RoundMode.TowardsZero: */ - return nameof(Sse41.RoundToZeroScalar); - } - } - - private static string GetVectorSse41NameRnd(RoundMode roundMode) - { - switch (roundMode) - { - case RoundMode.ToNearest: - return nameof(Sse41.RoundToNearestInteger); // even - - case RoundMode.TowardsPlusInfinity: - return nameof(Sse41.RoundToPositiveInfinity); - - case RoundMode.TowardsMinusInfinity: - return nameof(Sse41.RoundToNegativeInfinity); - - default: /* case RoundMode.TowardsZero: */ - return nameof(Sse41.RoundToZero); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdHash.cs b/ChocolArm64/Instructions/InstEmitSimdHash.cs deleted file mode 100644 index bb767fec..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdHash.cs +++ /dev/null @@ -1,140 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.Translation; - -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { -#region "Sha1" - public static void Sha1c_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - context.EmitLdvec(op.Rd); - EmitVectorExtractZx(context, op.Rn, 0, 2); - context.EmitLdvec(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.HashChoose)); - - context.EmitStvec(op.Rd); - } - - public static void Sha1h_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - EmitVectorExtractZx(context, op.Rn, 0, 2); - - SoftFallback.EmitCall(context, nameof(SoftFallback.FixedRotate)); - - EmitScalarSet(context, op.Rd, 2); - } - - public static void Sha1m_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - context.EmitLdvec(op.Rd); - EmitVectorExtractZx(context, op.Rn, 0, 2); - context.EmitLdvec(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.HashMajority)); - - context.EmitStvec(op.Rd); - } - - public static void Sha1p_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - context.EmitLdvec(op.Rd); - EmitVectorExtractZx(context, op.Rn, 0, 2); - context.EmitLdvec(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.HashParity)); - - context.EmitStvec(op.Rd); - } - - public static void Sha1su0_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.Sha1SchedulePart1)); - - context.EmitStvec(op.Rd); - } - - public static void Sha1su1_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - SoftFallback.EmitCall(context, nameof(SoftFallback.Sha1SchedulePart2)); - - context.EmitStvec(op.Rd); - } -#endregion - -#region "Sha256" - public static void Sha256h_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.HashLower)); - - context.EmitStvec(op.Rd); - } - - public static void Sha256h2_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.HashUpper)); - - context.EmitStvec(op.Rd); - } - - public static void Sha256su0_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - SoftFallback.EmitCall(context, nameof(SoftFallback.Sha256SchedulePart1)); - - context.EmitStvec(op.Rd); - } - - public static void Sha256su1_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - SoftFallback.EmitCall(context, nameof(SoftFallback.Sha256SchedulePart2)); - - context.EmitStvec(op.Rd); - } -#endregion - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdHelper.cs b/ChocolArm64/Instructions/InstEmitSimdHelper.cs deleted file mode 100644 index c8c8df74..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdHelper.cs +++ /dev/null @@ -1,1580 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace ChocolArm64.Instructions -{ - static class InstEmitSimdHelper - { - public static readonly Type[] IntTypesPerSizeLog2 = new Type[] - { - typeof(sbyte), - typeof(short), - typeof(int), - typeof(long) - }; - - public static readonly Type[] UIntTypesPerSizeLog2 = new Type[] - { - typeof(byte), - typeof(ushort), - typeof(uint), - typeof(ulong) - }; - - public static readonly Type[] VectorIntTypesPerSizeLog2 = new Type[] - { - typeof(Vector128<sbyte>), - typeof(Vector128<short>), - typeof(Vector128<int>), - typeof(Vector128<long>) - }; - - public static readonly Type[] VectorUIntTypesPerSizeLog2 = new Type[] - { - typeof(Vector128<byte>), - typeof(Vector128<ushort>), - typeof(Vector128<uint>), - typeof(Vector128<ulong>) - }; - - [Flags] - public enum OperFlags - { - Rd = 1 << 0, - Rn = 1 << 1, - Rm = 1 << 2, - Ra = 1 << 3, - - RnRm = Rn | Rm, - RdRn = Rd | Rn, - RaRnRm = Ra | Rn | Rm, - RdRnRm = Rd | Rn | Rm - } - - public static int GetImmShl(OpCodeSimdShImm64 op) - { - return op.Imm - (8 << op.Size); - } - - public static int GetImmShr(OpCodeSimdShImm64 op) - { - return (8 << (op.Size + 1)) - op.Imm; - } - - public static void EmitSse2Op(ILEmitterCtx context, string name) - { - EmitSseOp(context, name, typeof(Sse2)); - } - - public static void EmitSse41Op(ILEmitterCtx context, string name) - { - EmitSseOp(context, name, typeof(Sse41)); - } - - public static void EmitSse42Op(ILEmitterCtx context, string name) - { - EmitSseOp(context, name, typeof(Sse42)); - } - - private static void EmitSseOp(ILEmitterCtx context, string name, Type type) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdvec(op.Rn); - - Type baseType = VectorIntTypesPerSizeLog2[op.Size]; - - if (op is OpCodeSimdReg64 binOp) - { - context.EmitLdvec(binOp.Rm); - - context.EmitCall(type.GetMethod(name, new Type[] { baseType, baseType })); - } - else - { - context.EmitCall(type.GetMethod(name, new Type[] { baseType })); - } - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitScalarSseOrSse2OpF(ILEmitterCtx context, string name) - { - EmitSseOrSse2OpF(context, name, true); - } - - public static void EmitVectorSseOrSse2OpF(ILEmitterCtx context, string name) - { - EmitSseOrSse2OpF(context, name, false); - } - - public static void EmitSseOrSse2OpF(ILEmitterCtx context, string name, bool scalar) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - context.EmitLdvec(op.Rn); - - Type type; - Type baseType; - - if (sizeF == 0) - { - type = typeof(Sse); - baseType = typeof(Vector128<float>); - } - else /* if (sizeF == 1) */ - { - type = typeof(Sse2); - baseType = typeof(Vector128<double>); - } - - if (op is OpCodeSimdReg64 binOp) - { - context.EmitLdvec(binOp.Rm); - - context.EmitCall(type.GetMethod(name, new Type[] { baseType, baseType })); - } - else - { - context.EmitCall(type.GetMethod(name, new Type[] { baseType })); - } - - context.EmitStvec(op.Rd); - - if (scalar) - { - if (sizeF == 0) - { - EmitVectorZero32_128(context, op.Rd); - } - else /* if (sizeF == 1) */ - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitUnaryMathCall(ILEmitterCtx context, string name) - { - IOpCodeSimd64 op = (IOpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - MethodInfo mthdInfo; - - if (sizeF == 0) - { - mthdInfo = typeof(MathF).GetMethod(name, new Type[] { typeof(float) }); - } - else /* if (sizeF == 1) */ - { - mthdInfo = typeof(Math).GetMethod(name, new Type[] { typeof(double) }); - } - - context.EmitCall(mthdInfo); - } - - public static void EmitBinaryMathCall(ILEmitterCtx context, string name) - { - IOpCodeSimd64 op = (IOpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - MethodInfo mthdInfo; - - if (sizeF == 0) - { - mthdInfo = typeof(MathF).GetMethod(name, new Type[] { typeof(float), typeof(float) }); - } - else /* if (sizeF == 1) */ - { - mthdInfo = typeof(Math).GetMethod(name, new Type[] { typeof(double), typeof(double) }); - } - - context.EmitCall(mthdInfo); - } - - public static void EmitRoundMathCall(ILEmitterCtx context, MidpointRounding roundMode) - { - IOpCodeSimd64 op = (IOpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - MethodInfo mthdInfo; - - if (sizeF == 0) - { - mthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) }); - } - else /* if (sizeF == 1) */ - { - mthdInfo = typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) }); - } - - context.EmitLdc_I4((int)roundMode); - - context.EmitCall(mthdInfo); - } - - public static void EmitSoftFloatCall(ILEmitterCtx context, string name) - { - IOpCodeSimd64 op = (IOpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - Type type = sizeF == 0 - ? typeof(SoftFloat32) - : typeof(SoftFloat64); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCall(type, name); - } - - public static void EmitScalarBinaryOpByElemF(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElemF64 op = (OpCodeSimdRegElemF64)context.CurrOp; - - EmitScalarOpByElemF(context, emit, op.Index, ternary: false); - } - - public static void EmitScalarTernaryOpByElemF(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElemF64 op = (OpCodeSimdRegElemF64)context.CurrOp; - - EmitScalarOpByElemF(context, emit, op.Index, ternary: true); - } - - public static void EmitScalarOpByElemF(ILEmitterCtx context, Action emit, int elem, bool ternary) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (ternary) - { - EmitVectorExtractF(context, op.Rd, 0, sizeF); - } - - EmitVectorExtractF(context, op.Rn, 0, sizeF); - EmitVectorExtractF(context, op.Rm, elem, sizeF); - - emit(); - - EmitScalarSetF(context, op.Rd, sizeF); - } - - public static void EmitScalarUnaryOpSx(ILEmitterCtx context, Action emit) - { - EmitScalarOp(context, emit, OperFlags.Rn, true); - } - - public static void EmitScalarBinaryOpSx(ILEmitterCtx context, Action emit) - { - EmitScalarOp(context, emit, OperFlags.RnRm, true); - } - - public static void EmitScalarUnaryOpZx(ILEmitterCtx context, Action emit) - { - EmitScalarOp(context, emit, OperFlags.Rn, false); - } - - public static void EmitScalarBinaryOpZx(ILEmitterCtx context, Action emit) - { - EmitScalarOp(context, emit, OperFlags.RnRm, false); - } - - public static void EmitScalarTernaryOpZx(ILEmitterCtx context, Action emit) - { - EmitScalarOp(context, emit, OperFlags.RdRnRm, false); - } - - public static void EmitScalarOp(ILEmitterCtx context, Action emit, OperFlags opers, bool signed) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - bool rd = (opers & OperFlags.Rd) != 0; - bool rn = (opers & OperFlags.Rn) != 0; - bool rm = (opers & OperFlags.Rm) != 0; - - if (rd) - { - EmitVectorExtract(context, op.Rd, 0, op.Size, signed); - } - - if (rn) - { - EmitVectorExtract(context, op.Rn, 0, op.Size, signed); - } - - if (rm) - { - EmitVectorExtract(context, ((OpCodeSimdReg64)op).Rm, 0, op.Size, signed); - } - - emit(); - - EmitScalarSet(context, op.Rd, op.Size); - } - - public static void EmitScalarUnaryOpF(ILEmitterCtx context, Action emit) - { - EmitScalarOpF(context, emit, OperFlags.Rn); - } - - public static void EmitScalarBinaryOpF(ILEmitterCtx context, Action emit) - { - EmitScalarOpF(context, emit, OperFlags.RnRm); - } - - public static void EmitScalarTernaryRaOpF(ILEmitterCtx context, Action emit) - { - EmitScalarOpF(context, emit, OperFlags.RaRnRm); - } - - public static void EmitScalarOpF(ILEmitterCtx context, Action emit, OperFlags opers) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - bool ra = (opers & OperFlags.Ra) != 0; - bool rn = (opers & OperFlags.Rn) != 0; - bool rm = (opers & OperFlags.Rm) != 0; - - if (ra) - { - EmitVectorExtractF(context, ((OpCodeSimdReg64)op).Ra, 0, sizeF); - } - - if (rn) - { - EmitVectorExtractF(context, op.Rn, 0, sizeF); - } - - if (rm) - { - EmitVectorExtractF(context, ((OpCodeSimdReg64)op).Rm, 0, sizeF); - } - - emit(); - - EmitScalarSetF(context, op.Rd, sizeF); - } - - public static void EmitVectorUnaryOpF(ILEmitterCtx context, Action emit) - { - EmitVectorOpF(context, emit, OperFlags.Rn); - } - - public static void EmitVectorBinaryOpF(ILEmitterCtx context, Action emit) - { - EmitVectorOpF(context, emit, OperFlags.RnRm); - } - - public static void EmitVectorTernaryOpF(ILEmitterCtx context, Action emit) - { - EmitVectorOpF(context, emit, OperFlags.RdRnRm); - } - - public static void EmitVectorOpF(ILEmitterCtx context, Action emit, OperFlags opers) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> sizeF + 2; - - bool rd = (opers & OperFlags.Rd) != 0; - bool rn = (opers & OperFlags.Rn) != 0; - bool rm = (opers & OperFlags.Rm) != 0; - - for (int index = 0; index < elems; index++) - { - if (rd) - { - EmitVectorExtractF(context, op.Rd, index, sizeF); - } - - if (rn) - { - EmitVectorExtractF(context, op.Rn, index, sizeF); - } - - if (rm) - { - EmitVectorExtractF(context, ((OpCodeSimdReg64)op).Rm, index, sizeF); - } - - emit(); - - EmitVectorInsertF(context, op.Rd, index, sizeF); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitVectorBinaryOpByElemF(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElemF64 op = (OpCodeSimdRegElemF64)context.CurrOp; - - EmitVectorOpByElemF(context, emit, op.Index, ternary: false); - } - - public static void EmitVectorTernaryOpByElemF(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElemF64 op = (OpCodeSimdRegElemF64)context.CurrOp; - - EmitVectorOpByElemF(context, emit, op.Index, ternary: true); - } - - public static void EmitVectorOpByElemF(ILEmitterCtx context, Action emit, int elem, bool ternary) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> sizeF + 2; - - for (int index = 0; index < elems; index++) - { - if (ternary) - { - EmitVectorExtractF(context, op.Rd, index, sizeF); - } - - EmitVectorExtractF(context, op.Rn, index, sizeF); - EmitVectorExtractF(context, op.Rm, elem, sizeF); - - emit(); - - EmitVectorInsertTmpF(context, index, sizeF); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitVectorUnaryOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorOp(context, emit, OperFlags.Rn, true); - } - - public static void EmitVectorBinaryOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorOp(context, emit, OperFlags.RnRm, true); - } - - public static void EmitVectorTernaryOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorOp(context, emit, OperFlags.RdRnRm, true); - } - - public static void EmitVectorUnaryOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorOp(context, emit, OperFlags.Rn, false); - } - - public static void EmitVectorBinaryOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorOp(context, emit, OperFlags.RnRm, false); - } - - public static void EmitVectorTernaryOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorOp(context, emit, OperFlags.RdRnRm, false); - } - - public static void EmitVectorOp(ILEmitterCtx context, Action emit, OperFlags opers, bool signed) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - bool rd = (opers & OperFlags.Rd) != 0; - bool rn = (opers & OperFlags.Rn) != 0; - bool rm = (opers & OperFlags.Rm) != 0; - - for (int index = 0; index < elems; index++) - { - if (rd) - { - EmitVectorExtract(context, op.Rd, index, op.Size, signed); - } - - if (rn) - { - EmitVectorExtract(context, op.Rn, index, op.Size, signed); - } - - if (rm) - { - EmitVectorExtract(context, ((OpCodeSimdReg64)op).Rm, index, op.Size, signed); - } - - emit(); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitVectorBinaryOpByElemSx(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElem64 op = (OpCodeSimdRegElem64)context.CurrOp; - - EmitVectorOpByElem(context, emit, op.Index, ternary: false, signed: true); - } - - public static void EmitVectorBinaryOpByElemZx(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElem64 op = (OpCodeSimdRegElem64)context.CurrOp; - - EmitVectorOpByElem(context, emit, op.Index, ternary: false, signed: false); - } - - public static void EmitVectorTernaryOpByElemZx(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElem64 op = (OpCodeSimdRegElem64)context.CurrOp; - - EmitVectorOpByElem(context, emit, op.Index, ternary: true, signed: false); - } - - public static void EmitVectorOpByElem(ILEmitterCtx context, Action emit, int elem, bool ternary, bool signed) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - EmitVectorExtract(context, op.Rm, elem, op.Size, signed); - context.EmitSttmp(); - - for (int index = 0; index < elems; index++) - { - if (ternary) - { - EmitVectorExtract(context, op.Rd, index, op.Size, signed); - } - - EmitVectorExtract(context, op.Rn, index, op.Size, signed); - context.EmitLdtmp(); - - emit(); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitVectorImmUnaryOp(ILEmitterCtx context, Action emit) - { - EmitVectorImmOp(context, emit, false); - } - - public static void EmitVectorImmBinaryOp(ILEmitterCtx context, Action emit) - { - EmitVectorImmOp(context, emit, true); - } - - public static void EmitVectorImmOp(ILEmitterCtx context, Action emit, bool binary) - { - OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - if (binary) - { - EmitVectorExtractZx(context, op.Rd, index, op.Size); - } - - context.EmitLdc_I8(op.Imm); - - emit(); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitVectorWidenRmBinaryOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorWidenRmBinaryOp(context, emit, true); - } - - public static void EmitVectorWidenRmBinaryOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorWidenRmBinaryOp(context, emit, false); - } - - public static void EmitVectorWidenRmBinaryOp(ILEmitterCtx context, Action emit, bool signed) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size + 1, signed); - EmitVectorExtract(context, op.Rm, part + index, op.Size, signed); - - emit(); - - EmitVectorInsertTmp(context, index, op.Size + 1); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - } - - public static void EmitVectorWidenRnRmBinaryOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorWidenRnRmOp(context, emit, false, true); - } - - public static void EmitVectorWidenRnRmBinaryOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorWidenRnRmOp(context, emit, false, false); - } - - public static void EmitVectorWidenRnRmTernaryOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorWidenRnRmOp(context, emit, true, true); - } - - public static void EmitVectorWidenRnRmTernaryOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorWidenRnRmOp(context, emit, true, false); - } - - public static void EmitVectorWidenRnRmOp(ILEmitterCtx context, Action emit, bool ternary, bool signed) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - for (int index = 0; index < elems; index++) - { - if (ternary) - { - EmitVectorExtract(context, op.Rd, index, op.Size + 1, signed); - } - - EmitVectorExtract(context, op.Rn, part + index, op.Size, signed); - EmitVectorExtract(context, op.Rm, part + index, op.Size, signed); - - emit(); - - EmitVectorInsertTmp(context, index, op.Size + 1); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - } - - public static void EmitVectorWidenBinaryOpByElemSx(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElem64 op = (OpCodeSimdRegElem64)context.CurrOp; - - EmitVectorWidenOpByElem(context, emit, op.Index, ternary: false, signed: true); - } - - public static void EmitVectorWidenBinaryOpByElemZx(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElem64 op = (OpCodeSimdRegElem64)context.CurrOp; - - EmitVectorWidenOpByElem(context, emit, op.Index, ternary: false, signed: false); - } - - public static void EmitVectorWidenTernaryOpByElemSx(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElem64 op = (OpCodeSimdRegElem64)context.CurrOp; - - EmitVectorWidenOpByElem(context, emit, op.Index, ternary: true, signed: true); - } - - public static void EmitVectorWidenTernaryOpByElemZx(ILEmitterCtx context, Action emit) - { - OpCodeSimdRegElem64 op = (OpCodeSimdRegElem64)context.CurrOp; - - EmitVectorWidenOpByElem(context, emit, op.Index, ternary: true, signed: false); - } - - public static void EmitVectorWidenOpByElem(ILEmitterCtx context, Action emit, int elem, bool ternary, bool signed) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - EmitVectorExtract(context, op.Rm, elem, op.Size, signed); - context.EmitSttmp(); - - for (int index = 0; index < elems; index++) - { - if (ternary) - { - EmitVectorExtract(context, op.Rd, index, op.Size + 1, signed); - } - - EmitVectorExtract(context, op.Rn, part + index, op.Size, signed); - context.EmitLdtmp(); - - emit(); - - EmitVectorInsertTmp(context, index, op.Size + 1); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - } - - public static void EmitVectorPairwiseOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorPairwiseOp(context, emit, true); - } - - public static void EmitVectorPairwiseOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorPairwiseOp(context, emit, false); - } - - public static void EmitVectorPairwiseOp(ILEmitterCtx context, Action emit, bool signed) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int words = op.GetBitsCount() >> 4; - int pairs = words >> op.Size; - - for (int index = 0; index < pairs; index++) - { - int idx = index << 1; - - EmitVectorExtract(context, op.Rn, idx, op.Size, signed); - EmitVectorExtract(context, op.Rn, idx + 1, op.Size, signed); - - emit(); - - EmitVectorExtract(context, op.Rm, idx, op.Size, signed); - EmitVectorExtract(context, op.Rm, idx + 1, op.Size, signed); - - emit(); - - EmitVectorInsertTmp(context, pairs + index, op.Size); - EmitVectorInsertTmp(context, index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitVectorAcrossVectorOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorAcrossVectorOp(context, emit, signed: true, isLong: false); - } - - public static void EmitVectorAcrossVectorOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorAcrossVectorOp(context, emit, signed: false, isLong: false); - } - - public static void EmitVectorLongAcrossVectorOpSx(ILEmitterCtx context, Action emit) - { - EmitVectorAcrossVectorOp(context, emit, signed: true, isLong: true); - } - - public static void EmitVectorLongAcrossVectorOpZx(ILEmitterCtx context, Action emit) - { - EmitVectorAcrossVectorOp(context, emit, signed: false, isLong: true); - } - - public static void EmitVectorAcrossVectorOp( - ILEmitterCtx context, - Action emit, - bool signed, - bool isLong) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - EmitVectorExtract(context, op.Rn, 0, op.Size, signed); - - for (int index = 1; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size, signed); - - emit(); - } - - EmitScalarSet(context, op.Rd, isLong ? op.Size + 1 : op.Size); - } - - public static void EmitVectorPairwiseOpF(ILEmitterCtx context, Action emit) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - int words = op.GetBitsCount() >> 4; - int pairs = words >> sizeF + 2; - - for (int index = 0; index < pairs; index++) - { - int idx = index << 1; - - EmitVectorExtractF(context, op.Rn, idx, sizeF); - EmitVectorExtractF(context, op.Rn, idx + 1, sizeF); - - emit(); - - EmitVectorExtractF(context, op.Rm, idx, sizeF); - EmitVectorExtractF(context, op.Rm, idx + 1, sizeF); - - emit(); - - EmitVectorInsertTmpF(context, pairs + index, sizeF); - EmitVectorInsertTmpF(context, index, sizeF); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitVectorPairwiseSseOrSse2OpF(ILEmitterCtx context, string name) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - if (op.RegisterSize == RegisterSize.Simd64) - { - Type[] types = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.UnpackLow), types)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh), types)); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveHighToLow), types)); - - context.EmitCall(typeof(Sse).GetMethod(name, types)); - - context.EmitStvec(op.Rd); - } - else /* if (op.RegisterSize == RegisterSize.Simd128) */ - { - Type[] typesSfl = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>), typeof(byte) }; - Type[] types = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(2 << 6 | 0 << 4 | 2 << 2 | 0 << 0); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4(3 << 6 | 1 << 4 | 3 << 2 | 1 << 0); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse).GetMethod(name, types)); - - context.EmitStvec(op.Rd); - } - } - else /* if (sizeF == 1) */ - { - Type[] types = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackLow), types)); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); - - context.EmitCall(typeof(Sse2).GetMethod(name, types)); - - context.EmitStvec(op.Rd); - } - } - - [Flags] - public enum SaturatingFlags - { - Scalar = 1 << 0, - Signed = 1 << 1, - - Add = 1 << 2, - Sub = 1 << 3, - - Accumulate = 1 << 4, - - ScalarSx = Scalar | Signed, - ScalarZx = Scalar, - - VectorSx = Signed, - VectorZx = 0 - } - - public static void EmitScalarSaturatingUnaryOpSx(ILEmitterCtx context, Action emit) - { - EmitSaturatingUnaryOpSx(context, emit, SaturatingFlags.ScalarSx); - } - - public static void EmitVectorSaturatingUnaryOpSx(ILEmitterCtx context, Action emit) - { - EmitSaturatingUnaryOpSx(context, emit, SaturatingFlags.VectorSx); - } - - public static void EmitSaturatingUnaryOpSx(ILEmitterCtx context, Action emit, SaturatingFlags flags) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - bool scalar = (flags & SaturatingFlags.Scalar) != 0; - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> op.Size : 1; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractSx(context, op.Rn, index, op.Size); - - emit(); - - if (op.Size <= 2) - { - EmitSatQ(context, op.Size, true, true); - } - else /* if (op.Size == 3) */ - { - EmitUnarySignedSatQAbsOrNeg(context); - } - - if (scalar) - { - EmitVectorZeroAll(context, op.Rd); - } - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void EmitScalarSaturatingBinaryOpSx(ILEmitterCtx context, SaturatingFlags flags) - { - EmitSaturatingBinaryOp(context, () => { }, SaturatingFlags.ScalarSx | flags); - } - - public static void EmitScalarSaturatingBinaryOpZx(ILEmitterCtx context, SaturatingFlags flags) - { - EmitSaturatingBinaryOp(context, () => { }, SaturatingFlags.ScalarZx | flags); - } - - public static void EmitVectorSaturatingBinaryOpSx(ILEmitterCtx context, SaturatingFlags flags) - { - EmitSaturatingBinaryOp(context, () => { }, SaturatingFlags.VectorSx | flags); - } - - public static void EmitVectorSaturatingBinaryOpZx(ILEmitterCtx context, SaturatingFlags flags) - { - EmitSaturatingBinaryOp(context, () => { }, SaturatingFlags.VectorZx | flags); - } - - public static void EmitSaturatingBinaryOp(ILEmitterCtx context, Action emit, SaturatingFlags flags) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - bool scalar = (flags & SaturatingFlags.Scalar) != 0; - bool signed = (flags & SaturatingFlags.Signed) != 0; - - bool add = (flags & SaturatingFlags.Add) != 0; - bool sub = (flags & SaturatingFlags.Sub) != 0; - - bool accumulate = (flags & SaturatingFlags.Accumulate) != 0; - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> op.Size : 1; - - if (add || sub) - { - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size, signed); - EmitVectorExtract(context, ((OpCodeSimdReg64)op).Rm, index, op.Size, signed); - - if (op.Size <= 2) - { - context.Emit(add ? OpCodes.Add : OpCodes.Sub); - - EmitSatQ(context, op.Size, true, signed); - } - else /* if (op.Size == 3) */ - { - if (add) - { - EmitBinarySatQAdd(context, signed); - } - else /* if (sub) */ - { - EmitBinarySatQSub(context, signed); - } - } - - if (scalar) - { - EmitVectorZeroAll(context, op.Rd); - } - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - } - else if (accumulate) - { - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size, !signed); - EmitVectorExtract(context, op.Rd, index, op.Size, signed); - - if (op.Size <= 2) - { - context.Emit(OpCodes.Add); - - EmitSatQ(context, op.Size, true, signed); - } - else /* if (op.Size == 3) */ - { - EmitBinarySatQAccumulate(context, signed); - } - - if (scalar) - { - EmitVectorZeroAll(context, op.Rd); - } - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - } - else - { - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size, signed); - EmitVectorExtract(context, ((OpCodeSimdReg64)op).Rm, index, op.Size, signed); - - emit(); - - EmitSatQ(context, op.Size, true, signed); - - if (scalar) - { - EmitVectorZeroAll(context, op.Rd); - } - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - [Flags] - public enum SaturatingNarrowFlags - { - Scalar = 1 << 0, - SignedSrc = 1 << 1, - SignedDst = 1 << 2, - - ScalarSxSx = Scalar | SignedSrc | SignedDst, - ScalarSxZx = Scalar | SignedSrc, - ScalarZxZx = Scalar, - - VectorSxSx = SignedSrc | SignedDst, - VectorSxZx = SignedSrc, - VectorZxZx = 0 - } - - public static void EmitSaturatingNarrowOp(ILEmitterCtx context, SaturatingNarrowFlags flags) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - bool scalar = (flags & SaturatingNarrowFlags.Scalar) != 0; - bool signedSrc = (flags & SaturatingNarrowFlags.SignedSrc) != 0; - bool signedDst = (flags & SaturatingNarrowFlags.SignedDst) != 0; - - int elems = !scalar ? 8 >> op.Size : 1; - - int part = !scalar && (op.RegisterSize == RegisterSize.Simd128) ? elems : 0; - - if (scalar) - { - EmitVectorZeroLowerTmp(context); - } - - if (part != 0) - { - context.EmitLdvec(op.Rd); - context.EmitStvectmp(); - } - - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size + 1, signedSrc); - - EmitSatQ(context, op.Size, signedSrc, signedDst); - - EmitVectorInsertTmp(context, part + index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (part == 0) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - // TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned). - public static void EmitSatQ(ILEmitterCtx context, int sizeDst, bool signedSrc, bool signedDst) - { - if ((uint)sizeDst > 2u) - { - throw new ArgumentOutOfRangeException(nameof(sizeDst)); - } - - context.EmitLdc_I4(sizeDst); - context.EmitLdarg(TranslatedSub.StateArgIdx); - - if (signedSrc) - { - SoftFallback.EmitCall(context, signedDst - ? nameof(SoftFallback.SignedSrcSignedDstSatQ) - : nameof(SoftFallback.SignedSrcUnsignedDstSatQ)); - } - else - { - SoftFallback.EmitCall(context, signedDst - ? nameof(SoftFallback.UnsignedSrcSignedDstSatQ) - : nameof(SoftFallback.UnsignedSrcUnsignedDstSatQ)); - } - } - - // TSrc (64bit) == TDst (64bit); signed. - public static void EmitUnarySignedSatQAbsOrNeg(ILEmitterCtx context) - { - if (((OpCodeSimd64)context.CurrOp).Size < 3) - { - throw new InvalidOperationException(); - } - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, nameof(SoftFallback.UnarySignedSatQAbsOrNeg)); - } - - // TSrcs (64bit) == TDst (64bit); signed, unsigned. - public static void EmitBinarySatQAdd(ILEmitterCtx context, bool signed) - { - if (((OpCodeSimdReg64)context.CurrOp).Size < 3) - { - throw new InvalidOperationException(); - } - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, signed - ? nameof(SoftFallback.BinarySignedSatQAdd) - : nameof(SoftFallback.BinaryUnsignedSatQAdd)); - } - - // TSrcs (64bit) == TDst (64bit); signed, unsigned. - public static void EmitBinarySatQSub(ILEmitterCtx context, bool signed) - { - if (((OpCodeSimdReg64)context.CurrOp).Size < 3) - { - throw new InvalidOperationException(); - } - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, signed - ? nameof(SoftFallback.BinarySignedSatQSub) - : nameof(SoftFallback.BinaryUnsignedSatQSub)); - } - - // TSrcs (64bit) == TDst (64bit); signed, unsigned. - public static void EmitBinarySatQAccumulate(ILEmitterCtx context, bool signed) - { - if (((OpCodeSimd64)context.CurrOp).Size < 3) - { - throw new InvalidOperationException(); - } - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, signed - ? nameof(SoftFallback.BinarySignedSatQAcc) - : nameof(SoftFallback.BinaryUnsignedSatQAcc)); - } - - public static void EmitScalarSet(ILEmitterCtx context, int reg, int size) - { - EmitVectorZeroAll(context, reg); - EmitVectorInsert(context, reg, 0, size); - } - - public static void EmitScalarSetF(ILEmitterCtx context, int reg, int size) - { - if (Optimizations.UseSse41 && size == 0) - { - // If the type is float, we can perform insertion and - // zero the upper bits with a single instruction (INSERTPS); - context.EmitLdvec(reg); - - VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41VectorInsertScalarSingle)); - - context.EmitStvec(reg); - } - else - { - EmitVectorZeroAll(context, reg); - EmitVectorInsertF(context, reg, 0, size); - } - } - - public static void EmitVectorExtractSx(ILEmitterCtx context, int reg, int index, int size) - { - EmitVectorExtract(context, reg, index, size, true); - } - - public static void EmitVectorExtractZx(ILEmitterCtx context, int reg, int index, int size) - { - EmitVectorExtract(context, reg, index, size, false); - } - - public static void EmitVectorExtract(ILEmitterCtx context, int reg, int index, int size, bool signed) - { - ThrowIfInvalid(index, size); - - context.EmitLdvec(reg); - context.EmitLdc_I4(index); - context.EmitLdc_I4(size); - - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.VectorExtractIntSx) - : nameof(VectorHelper.VectorExtractIntZx)); - } - - public static void EmitVectorExtractF(ILEmitterCtx context, int reg, int index, int size) - { - ThrowIfInvalidF(index, size); - - context.EmitLdvec(reg); - context.EmitLdc_I4(index); - - if (size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractSingle)); - } - else if (size == 1) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - - public static void EmitVectorZeroAll(ILEmitterCtx context, int reg) - { - if (Optimizations.UseSse) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitStvec(reg); - } - else - { - EmitVectorZeroLower(context, reg); - EmitVectorZeroUpper(context, reg); - } - } - - public static void EmitVectorZeroLower(ILEmitterCtx context, int reg) - { - EmitVectorInsert(context, reg, 0, 3, 0); - } - - public static void EmitVectorZeroLowerTmp(ILEmitterCtx context) - { - if (Optimizations.UseSse) - { - context.EmitLdvectmp(); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveHighToLow))); - - context.EmitStvectmp(); - } - else - { - EmitVectorInsertTmp(context, 0, 3, 0); - } - } - - public static void EmitVectorZeroUpper(ILEmitterCtx context, int reg) - { - if (Optimizations.UseSse) - { - // TODO: Use Sse2.MoveScalar once it is fixed (in .NET Core 3.0), - // as of the time of writing it just crashes the JIT. - - /*Type[] typesMov = new Type[] { typeof(Vector128<ulong>) }; - - context.EmitLdvec(reg); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MoveScalar), typesMov)); - - context.EmitStvec(reg);*/ - - context.EmitLdvec(reg); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - - context.EmitStvec(reg); - } - else - { - EmitVectorInsert(context, reg, 1, 3, 0); - } - } - - public static void EmitVectorZero32_128(ILEmitterCtx context, int reg) - { - if (!Sse.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - context.EmitLdvec(reg); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveScalar))); - - context.EmitStvec(reg); - } - - public static void EmitVectorInsert(ILEmitterCtx context, int reg, int index, int size) - { - ThrowIfInvalid(index, size); - - context.EmitLdvec(reg); - context.EmitLdc_I4(index); - context.EmitLdc_I4(size); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertInt)); - - context.EmitStvec(reg); - } - - public static void EmitVectorInsertTmp(ILEmitterCtx context, int index, int size) - { - ThrowIfInvalid(index, size); - - context.EmitLdvectmp(); - context.EmitLdc_I4(index); - context.EmitLdc_I4(size); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertInt)); - - context.EmitStvectmp(); - } - - public static void EmitVectorInsert(ILEmitterCtx context, int reg, int index, int size, long value) - { - ThrowIfInvalid(index, size); - - context.EmitLdc_I8(value); - context.EmitLdvec(reg); - context.EmitLdc_I4(index); - context.EmitLdc_I4(size); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertInt)); - - context.EmitStvec(reg); - } - - public static void EmitVectorInsertTmp(ILEmitterCtx context, int index, int size, long value) - { - ThrowIfInvalid(index, size); - - context.EmitLdc_I8(value); - context.EmitLdvectmp(); - context.EmitLdc_I4(index); - context.EmitLdc_I4(size); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertInt)); - - context.EmitStvectmp(); - } - - public static void EmitVectorInsertF(ILEmitterCtx context, int reg, int index, int size) - { - ThrowIfInvalidF(index, size); - - context.EmitLdvec(reg); - context.EmitLdc_I4(index); - - if (size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertSingle)); - } - else if (size == 1) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - context.EmitStvec(reg); - } - - public static void EmitVectorInsertTmpF(ILEmitterCtx context, int index, int size) - { - ThrowIfInvalidF(index, size); - - context.EmitLdvectmp(); - context.EmitLdc_I4(index); - - if (size == 0) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertSingle)); - } - else if (size == 1) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInsertDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - context.EmitStvectmp(); - } - - private static void ThrowIfInvalid(int index, int size) - { - if ((uint)size > 3u) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - if ((uint)index >= 16u >> size) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - - private static void ThrowIfInvalidF(int index, int size) - { - if ((uint)size > 1u) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - if ((uint)index >= 4u >> size) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdLogical.cs b/ChocolArm64/Instructions/InstEmitSimdLogical.cs deleted file mode 100644 index a5a92274..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdLogical.cs +++ /dev/null @@ -1,437 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void And_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - EmitSse2Op(context, nameof(Sse2.And)); - } - else - { - EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.And)); - } - } - - public static void Bic_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesAnt = new Type[] { typeof(Vector128<byte>), typeof(Vector128<byte>) }; - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpZx(context, () => - { - context.Emit(OpCodes.Not); - context.Emit(OpCodes.And); - }); - } - } - - public static void Bic_Vi(ILEmitterCtx context) - { - EmitVectorImmBinaryOp(context, () => - { - context.Emit(OpCodes.Not); - context.Emit(OpCodes.And); - }); - } - - public static void Bif_V(ILEmitterCtx context) - { - EmitBifBit(context, notRm: true); - } - - public static void Bit_V(ILEmitterCtx context) - { - EmitBifBit(context, notRm: false); - } - - private static void EmitBifBit(ILEmitterCtx context, bool notRm) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2) - { - Type[] typesXorAnd = new Type[] { typeof(Vector128<byte>), typeof(Vector128<byte>) }; - - string nameAnd = notRm ? nameof(Sse2.AndNot) : nameof(Sse2.And); - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rd); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); - context.EmitCall(typeof(Sse2).GetMethod(nameAnd, typesXorAnd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - int elems = op.RegisterSize == RegisterSize.Simd128 ? 2 : 1; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rd, index, 3); - context.Emit(OpCodes.Dup); - - EmitVectorExtractZx(context, op.Rn, index, 3); - - context.Emit(OpCodes.Xor); - - EmitVectorExtractZx(context, op.Rm, index, 3); - - if (notRm) - { - context.Emit(OpCodes.Not); - } - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Xor); - - EmitVectorInsert(context, op.Rd, index, 3); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - public static void Bsl_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesXorAnd = new Type[] { typeof(Vector128<byte>), typeof(Vector128<byte>) }; - - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rm); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); - - context.EmitLdvec(op.Rd); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesXorAnd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorTernaryOpZx(context, () => - { - context.EmitSttmp(); - context.EmitLdtmp(); - - context.Emit(OpCodes.Xor); - context.Emit(OpCodes.And); - - context.EmitLdtmp(); - - context.Emit(OpCodes.Xor); - }); - } - } - - public static void Eor_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - EmitSse2Op(context, nameof(Sse2.Xor)); - } - else - { - EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Xor)); - } - } - - public static void Not_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesSav = new Type[] { typeof(long) }; - Type[] typesAnt = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I8(-1L); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorUnaryOpZx(context, () => context.Emit(OpCodes.Not)); - } - } - - public static void Orn_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - Type[] typesSav = new Type[] { typeof(long) }; - Type[] typesAntOr = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I8(-1L); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAntOr)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAntOr)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorBinaryOpZx(context, () => - { - context.Emit(OpCodes.Not); - context.Emit(OpCodes.Or); - }); - } - } - - public static void Orr_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - EmitSse2Op(context, nameof(Sse2.Or)); - } - else - { - EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Or)); - } - } - - public static void Orr_Vi(ILEmitterCtx context) - { - EmitVectorImmBinaryOp(context, () => context.Emit(OpCodes.Or)); - } - - public static void Rbit_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, 0); - - context.Emit(OpCodes.Conv_U4); - - SoftFallback.EmitCall(context, nameof(SoftFallback.ReverseBits8)); - - context.Emit(OpCodes.Conv_U8); - - EmitVectorInsert(context, op.Rd, index, 0); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Rev16_V(ILEmitterCtx context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - Type[] typesSfl = new Type[] { typeof(Vector128<sbyte>), typeof(Vector128<sbyte>) }; - - context.EmitLdvec(op.Rn); // value - - context.EmitLdc_I8(14L << 56 | 15L << 48 | 12L << 40 | 13L << 32 | 10L << 24 | 11L << 16 | 08L << 8 | 09L << 0); // maskE1 - context.EmitLdc_I8(06L << 56 | 07L << 48 | 04L << 40 | 05L << 32 | 02L << 24 | 03L << 16 | 00L << 8 | 01L << 0); // maskE0 - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitRev_V(context, containerSize: 1); - } - } - - public static void Rev32_V(ILEmitterCtx context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - Type[] typesSfl = new Type[] { typeof(Vector128<sbyte>), typeof(Vector128<sbyte>) }; - - context.EmitLdvec(op.Rn); // value - - if (op.Size == 0) - { - context.EmitLdc_I8(12L << 56 | 13L << 48 | 14L << 40 | 15L << 32 | 08L << 24 | 09L << 16 | 10L << 8 | 11L << 0); // maskE1 - context.EmitLdc_I8(04L << 56 | 05L << 48 | 06L << 40 | 07L << 32 | 00L << 24 | 01L << 16 | 02L << 8 | 03L << 0); // maskE0 - } - else /* if (op.Size == 1) */ - { - context.EmitLdc_I8(13L << 56 | 12L << 48 | 15L << 40 | 14L << 32 | 09L << 24 | 08L << 16 | 11L << 8 | 10L << 0); // maskE1 - context.EmitLdc_I8(05L << 56 | 04L << 48 | 07L << 40 | 06L << 32 | 01L << 24 | 00L << 16 | 03L << 8 | 02L << 0); // maskE0 - } - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitRev_V(context, containerSize: 2); - } - } - - public static void Rev64_V(ILEmitterCtx context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - Type[] typesSfl = new Type[] { typeof(Vector128<sbyte>), typeof(Vector128<sbyte>) }; - - context.EmitLdvec(op.Rn); // value - - if (op.Size == 0) - { - context.EmitLdc_I8(08L << 56 | 09L << 48 | 10L << 40 | 11L << 32 | 12L << 24 | 13L << 16 | 14L << 8 | 15L << 0); // maskE1 - context.EmitLdc_I8(00L << 56 | 01L << 48 | 02L << 40 | 03L << 32 | 04L << 24 | 05L << 16 | 06L << 8 | 07L << 0); // maskE0 - } - else if (op.Size == 1) - { - context.EmitLdc_I8(09L << 56 | 08L << 48 | 11L << 40 | 10L << 32 | 13L << 24 | 12L << 16 | 15L << 8 | 14L << 0); // maskE1 - context.EmitLdc_I8(01L << 56 | 00L << 48 | 03L << 40 | 02L << 32 | 05L << 24 | 04L << 16 | 07L << 8 | 06L << 0); // maskE0 - } - else /* if (op.Size == 2) */ - { - context.EmitLdc_I8(11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 15L << 24 | 14L << 16 | 13L << 8 | 12L << 0); // maskE1 - context.EmitLdc_I8(03L << 56 | 02L << 48 | 01L << 40 | 00L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0); // maskE0 - } - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitRev_V(context, containerSize: 3); - } - } - - private static void EmitRev_V(ILEmitterCtx context, int containerSize) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - int containerMask = (1 << (containerSize - op.Size)) - 1; - - for (int index = 0; index < elems; index++) - { - int revIndex = index ^ containerMask; - - EmitVectorExtractZx(context, op.Rn, revIndex, op.Size); - - EmitVectorInsertTmp(context, index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdMemory.cs b/ChocolArm64/Instructions/InstEmitSimdMemory.cs deleted file mode 100644 index 073b0f0a..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdMemory.cs +++ /dev/null @@ -1,182 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instructions.InstEmitMemoryHelper; -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Ld__Vms(ILEmitterCtx context) - { - EmitSimdMemMs(context, isLoad: true); - } - - public static void Ld__Vss(ILEmitterCtx context) - { - EmitSimdMemSs(context, isLoad: true); - } - - public static void St__Vms(ILEmitterCtx context) - { - EmitSimdMemMs(context, isLoad: false); - } - - public static void St__Vss(ILEmitterCtx context) - { - EmitSimdMemSs(context, isLoad: false); - } - - private static void EmitSimdMemMs(ILEmitterCtx context, bool isLoad) - { - OpCodeSimdMemMs64 op = (OpCodeSimdMemMs64)context.CurrOp; - - int offset = 0; - - for (int rep = 0; rep < op.Reps; rep++) - for (int elem = 0; elem < op.Elems; elem++) - for (int sElem = 0; sElem < op.SElems; sElem++) - { - int rtt = (op.Rt + rep + sElem) & 0x1f; - - if (isLoad) - { - context.EmitLdint(op.Rn); - context.EmitLdc_I8(offset); - - context.Emit(OpCodes.Add); - - EmitReadZxCall(context, op.Size); - - EmitVectorInsert(context, rtt, elem, op.Size); - - if (op.RegisterSize == RegisterSize.Simd64 && elem == op.Elems - 1) - { - EmitVectorZeroUpper(context, rtt); - } - } - else - { - context.EmitLdint(op.Rn); - context.EmitLdc_I8(offset); - - context.Emit(OpCodes.Add); - - EmitVectorExtractZx(context, rtt, elem, op.Size); - - EmitWriteCall(context, op.Size); - } - - offset += 1 << op.Size; - } - - if (op.WBack) - { - EmitSimdMemWBack(context, offset); - } - } - - private static void EmitSimdMemSs(ILEmitterCtx context, bool isLoad) - { - OpCodeSimdMemSs64 op = (OpCodeSimdMemSs64)context.CurrOp; - - int offset = 0; - - void EmitMemAddress() - { - context.EmitLdint(op.Rn); - context.EmitLdc_I8(offset); - - context.Emit(OpCodes.Add); - } - - if (op.Replicate) - { - // Only loads uses the replicate mode. - if (!isLoad) - { - throw new InvalidOperationException(); - } - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int sElem = 0; sElem < op.SElems; sElem++) - { - int rt = (op.Rt + sElem) & 0x1f; - - for (int index = 0; index < elems; index++) - { - EmitMemAddress(); - - EmitReadZxCall(context, op.Size); - - EmitVectorInsert(context, rt, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, rt); - } - - offset += 1 << op.Size; - } - } - else - { - for (int sElem = 0; sElem < op.SElems; sElem++) - { - int rt = (op.Rt + sElem) & 0x1f; - - if (isLoad) - { - EmitMemAddress(); - - EmitReadZxCall(context, op.Size); - - EmitVectorInsert(context, rt, op.Index, op.Size); - } - else - { - EmitMemAddress(); - - EmitVectorExtractZx(context, rt, op.Index, op.Size); - - EmitWriteCall(context, op.Size); - } - - offset += 1 << op.Size; - } - } - - if (op.WBack) - { - EmitSimdMemWBack(context, offset); - } - } - - private static void EmitSimdMemWBack(ILEmitterCtx context, int offset) - { - OpCodeMemReg64 op = (OpCodeMemReg64)context.CurrOp; - - context.EmitLdint(op.Rn); - - if (op.Rm != RegisterAlias.Zr) - { - context.EmitLdint(op.Rm); - } - else - { - context.EmitLdc_I8(offset); - } - - context.Emit(OpCodes.Add); - - context.EmitStint(op.Rn); - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitSimdMove.cs b/ChocolArm64/Instructions/InstEmitSimdMove.cs deleted file mode 100644 index 647a2238..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdMove.cs +++ /dev/null @@ -1,793 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.IntermediateRepresentation; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { -#region "Masks" - private static readonly long[] _masksE0_TrnUzpXtn = new long[] - { - 14L << 56 | 12L << 48 | 10L << 40 | 08L << 32 | 06L << 24 | 04L << 16 | 02L << 8 | 00L << 0, - 13L << 56 | 12L << 48 | 09L << 40 | 08L << 32 | 05L << 24 | 04L << 16 | 01L << 8 | 00L << 0, - 11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0 - }; - - private static readonly long[] _masksE1_TrnUzp = new long[] - { - 15L << 56 | 13L << 48 | 11L << 40 | 09L << 32 | 07L << 24 | 05L << 16 | 03L << 8 | 01L << 0, - 15L << 56 | 14L << 48 | 11L << 40 | 10L << 32 | 07L << 24 | 06L << 16 | 03L << 8 | 02L << 0, - 15L << 56 | 14L << 48 | 13L << 40 | 12L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0 - }; - - private static readonly long[] _masksE0_Uzp = new long[] - { - 13L << 56 | 09L << 48 | 05L << 40 | 01L << 32 | 12L << 24 | 08L << 16 | 04L << 8 | 00L << 0, - 11L << 56 | 10L << 48 | 03L << 40 | 02L << 32 | 09L << 24 | 08L << 16 | 01L << 8 | 00L << 0 - }; - - private static readonly long[] _masksE1_Uzp = new long[] - { - 15L << 56 | 11L << 48 | 07L << 40 | 03L << 32 | 14L << 24 | 10L << 16 | 06L << 8 | 02L << 0, - 15L << 56 | 14L << 48 | 07L << 40 | 06L << 32 | 13L << 24 | 12L << 16 | 05L << 8 | 04L << 0 - }; -#endregion - - public static void Dup_Gp(ILEmitterCtx context) - { - OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp; - - if (Optimizations.UseSse2) - { - Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdintzr(op.Rn); - - switch (op.Size) - { - case 0: context.Emit(OpCodes.Conv_U1); break; - case 1: context.Emit(OpCodes.Conv_U2); break; - case 2: context.Emit(OpCodes.Conv_U4); break; - } - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvec(op.Rd); - } - else - { - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - context.EmitLdintzr(op.Rn); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Dup_S(ILEmitterCtx context) - { - OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp; - - EmitVectorExtractZx(context, op.Rn, op.DstIndex, op.Size); - - EmitScalarSet(context, op.Rd, op.Size); - } - - public static void Dup_V(ILEmitterCtx context) - { - OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp; - - if (Optimizations.UseSse2) - { - Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size] }; - - EmitVectorExtractZx(context, op.Rn, op.DstIndex, op.Size); - - switch (op.Size) - { - case 0: context.Emit(OpCodes.Conv_U1); break; - case 1: context.Emit(OpCodes.Conv_U2); break; - case 2: context.Emit(OpCodes.Conv_U4); break; - } - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvec(op.Rd); - } - else - { - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, op.DstIndex, op.Size); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Ext_V(ILEmitterCtx context) - { - OpCodeSimdExt64 op = (OpCodeSimdExt64)context.CurrOp; - - if (Optimizations.UseSse2) - { - Type[] typesShs = new Type[] { typeof(Vector128<byte>), typeof(byte) }; - Type[] typesOr = new Type[] { typeof(Vector128<byte>), typeof(Vector128<byte>) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd64) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - } - - context.EmitLdc_I4(op.Imm4); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesShs)); - - context.EmitLdvec(op.Rm); - - context.EmitLdc_I4((op.RegisterSize == RegisterSize.Simd64 ? 8 : 16) - op.Imm4); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical128BitLane), typesShs)); - - if (op.RegisterSize == RegisterSize.Simd64) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - } - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); - - context.EmitStvec(op.Rd); - } - else - { - int bytes = op.GetBitsCount() >> 3; - - int position = op.Imm4; - - for (int index = 0; index < bytes; index++) - { - int reg = op.Imm4 + index < bytes ? op.Rn : op.Rm; - - if (position == bytes) - { - position = 0; - } - - EmitVectorExtractZx(context, reg, position++, 0); - EmitVectorInsertTmp(context, index, 0); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - public static void Fcsel_S(ILEmitterCtx context) - { - OpCodeSimdFcond64 op = (OpCodeSimdFcond64)context.CurrOp; - - ILLabel lblTrue = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - - context.EmitCondBranch(lblTrue, op.Cond); - - EmitVectorExtractF(context, op.Rm, 0, op.Size); - - context.Emit(OpCodes.Br_S, lblEnd); - - context.MarkLabel(lblTrue); - - EmitVectorExtractF(context, op.Rn, 0, op.Size); - - context.MarkLabel(lblEnd); - - EmitScalarSetF(context, op.Rd, op.Size); - } - - public static void Fmov_Ftoi(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - EmitVectorExtractZx(context, op.Rn, 0, op.Size + 2); - - context.EmitStintzr(op.Rd); - } - - public static void Fmov_Ftoi1(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - EmitVectorExtractZx(context, op.Rn, 1, 3); - - context.EmitStintzr(op.Rd); - } - - public static void Fmov_Itof(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - EmitScalarSet(context, op.Rd, op.Size + 2); - } - - public static void Fmov_Itof1(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - EmitVectorInsert(context, op.Rd, 1, 3); - } - - public static void Fmov_S(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - EmitVectorExtractF(context, op.Rn, 0, op.Size); - - EmitScalarSetF(context, op.Rd, op.Size); - } - - public static void Fmov_Si(ILEmitterCtx context) - { - OpCodeSimdFmov64 op = (OpCodeSimdFmov64)context.CurrOp; - - context.EmitLdc_I8(op.Imm); - - EmitScalarSet(context, op.Rd, op.Size + 2); - } - - public static void Fmov_Vi(ILEmitterCtx context) - { - OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp; - - int elems = op.RegisterSize == RegisterSize.Simd128 ? 4 : 2; - - for (int index = 0; index < (elems >> op.Size); index++) - { - context.EmitLdc_I8(op.Imm); - - EmitVectorInsert(context, op.Rd, index, op.Size + 2); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Ins_Gp(ILEmitterCtx context) - { - OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp; - - context.EmitLdintzr(op.Rn); - - EmitVectorInsert(context, op.Rd, op.DstIndex, op.Size); - } - - public static void Ins_V(ILEmitterCtx context) - { - OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp; - - EmitVectorExtractZx(context, op.Rn, op.SrcIndex, op.Size); - - EmitVectorInsert(context, op.Rd, op.DstIndex, op.Size); - } - - public static void Movi_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - EmitMoviMvni(context, not: false); - } - else - { - EmitVectorImmUnaryOp(context, () => { }); - } - } - - public static void Mvni_V(ILEmitterCtx context) - { - if (Optimizations.UseSse2) - { - EmitMoviMvni(context, not: true); - } - else - { - EmitVectorImmUnaryOp(context, () => context.Emit(OpCodes.Not)); - } - } - - public static void Smov_S(ILEmitterCtx context) - { - OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp; - - EmitVectorExtractSx(context, op.Rn, op.DstIndex, op.Size); - - if (op.RegisterSize == RegisterSize.Simd64) - { - context.Emit(OpCodes.Conv_U4); - context.Emit(OpCodes.Conv_U8); - } - - context.EmitStintzr(op.Rd); - } - - public static void Tbl_V(ILEmitterCtx context) - { - OpCodeSimdTbl64 op = (OpCodeSimdTbl64)context.CurrOp; - - if (Optimizations.UseSsse3) - { - Type[] typesCmpSflSub = new Type[] { typeof(Vector128<sbyte>), typeof(Vector128<sbyte>) }; - Type[] typesOr = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) }; - Type[] typesSav = new Type[] { typeof(long) }; - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I8(0x0F0F0F0F0F0F0F0FL); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvectmp2(); - context.EmitLdvectmp2(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSflSub)); - - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesCmpSflSub)); - - for (int index = 1; index < op.Size; index++) - { - context.EmitLdvec((op.Rn + index) & 0x1F); - context.EmitLdvec(op.Rm); - - context.EmitLdc_I8(0x1010101010101010L * index); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSflSub)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitLdvectmp2(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSflSub)); - - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesCmpSflSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); - } - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - context.EmitLdvec(op.Rm); - - for (int index = 0; index < op.Size; index++) - { - context.EmitLdvec((op.Rn + index) & 0x1F); - } - - switch (op.Size) - { - case 1: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl1_V64), - nameof(VectorHelper.Tbl1_V128)); break; - - case 2: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl2_V64), - nameof(VectorHelper.Tbl2_V128)); break; - - case 3: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl3_V64), - nameof(VectorHelper.Tbl3_V128)); break; - - case 4: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl4_V64), - nameof(VectorHelper.Tbl4_V128)); break; - - default: throw new InvalidOperationException(); - } - - context.EmitStvec(op.Rd); - } - } - - public static void Trn1_V(ILEmitterCtx context) - { - EmitVectorTranspose(context, part: 0); - } - - public static void Trn2_V(ILEmitterCtx context) - { - EmitVectorTranspose(context, part: 1); - } - - public static void Umov_S(ILEmitterCtx context) - { - OpCodeSimdIns64 op = (OpCodeSimdIns64)context.CurrOp; - - EmitVectorExtractZx(context, op.Rn, op.DstIndex, op.Size); - - context.EmitStintzr(op.Rd); - } - - public static void Uzp1_V(ILEmitterCtx context) - { - EmitVectorUnzip(context, part: 0); - } - - public static void Uzp2_V(ILEmitterCtx context) - { - EmitVectorUnzip(context, part: 1); - } - - public static void Xtn_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - if (Optimizations.UseSsse3) - { - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - - string nameMov = op.RegisterSize == RegisterSize.Simd128 - ? nameof(Sse.MoveLowToHigh) - : nameof(Sse.MoveHighToLow); - - context.EmitLdvec(op.Rd); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - - context.EmitLdvec(op.Rn); // value - - context.EmitLdc_I8(_masksE0_TrnUzpXtn[op.Size]); // mask - context.Emit(OpCodes.Dup); // mask - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); - - context.EmitCall(typeof(Sse).GetMethod(nameMov)); - - context.EmitStvec(op.Rd); - } - else - { - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - if (part != 0) - { - context.EmitLdvec(op.Rd); - context.EmitStvectmp(); - } - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size + 1); - - EmitVectorInsertTmp(context, part + index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (part == 0) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - public static void Zip1_V(ILEmitterCtx context) - { - EmitVectorZip(context, part: 0); - } - - public static void Zip2_V(ILEmitterCtx context) - { - EmitVectorZip(context, part: 1); - } - - private static void EmitMoviMvni(ILEmitterCtx context, bool not) - { - OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp; - - Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size] }; - - long imm = op.Imm; - - if (not) - { - imm = ~imm; - } - - if (op.Size < 3) - { - context.EmitLdc_I4((int)imm); - } - else - { - context.EmitLdc_I8(imm); - } - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitVectorTranspose(ILEmitterCtx context, int part) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSsse3) - { - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - - string nameUpk = part == 0 - ? nameof(Sse2.UnpackLow) - : nameof(Sse2.UnpackHigh); - - context.EmitLdvec(op.Rn); // value - - if (op.Size < 3) - { - context.EmitLdc_I8(_masksE1_TrnUzp [op.Size]); // maskE1 - context.EmitLdc_I8(_masksE0_TrnUzpXtn[op.Size]); // maskE0 - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); - } - - context.EmitLdvec(op.Rm); // value - - if (op.Size < 3) - { - context.EmitLdc_I8(_masksE1_TrnUzp [op.Size]); // maskE1 - context.EmitLdc_I8(_masksE0_TrnUzpXtn[op.Size]); // maskE0 - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); - } - - context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(op.Size))); - - context.EmitStvec(op.Rd); - } - else - { - int words = op.GetBitsCount() >> 4; - int pairs = words >> op.Size; - - for (int index = 0; index < pairs; index++) - { - int idx = index << 1; - - EmitVectorExtractZx(context, op.Rn, idx + part, op.Size); - EmitVectorExtractZx(context, op.Rm, idx + part, op.Size); - - EmitVectorInsertTmp(context, idx + 1, op.Size); - EmitVectorInsertTmp(context, idx, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitVectorUnzip(ILEmitterCtx context, int part) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSsse3) - { - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - - string nameUpk = part == 0 - ? nameof(Sse2.UnpackLow) - : nameof(Sse2.UnpackHigh); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.EmitLdvec(op.Rn); // value - - if (op.Size < 3) - { - context.EmitLdc_I8(_masksE1_TrnUzp [op.Size]); // maskE1 - context.EmitLdc_I8(_masksE0_TrnUzpXtn[op.Size]); // maskE0 - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); - } - - context.EmitLdvec(op.Rm); // value - - if (op.Size < 3) - { - context.EmitLdc_I8(_masksE1_TrnUzp [op.Size]); // maskE1 - context.EmitLdc_I8(_masksE0_TrnUzpXtn[op.Size]); // maskE0 - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); - } - - context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); - - context.EmitStvec(op.Rd); - } - else - { - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackLow), GetTypesSflUpk(op.Size))); // value - - if (op.Size < 2) - { - context.EmitLdc_I8(_masksE1_Uzp[op.Size]); // maskE1 - context.EmitLdc_I8(_masksE0_Uzp[op.Size]); // maskE0 - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); - } - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); - - context.EmitStvec(op.Rd); - } - } - else - { - int words = op.GetBitsCount() >> 4; - int pairs = words >> op.Size; - - for (int index = 0; index < pairs; index++) - { - int idx = index << 1; - - EmitVectorExtractZx(context, op.Rn, idx + part, op.Size); - EmitVectorExtractZx(context, op.Rm, idx + part, op.Size); - - EmitVectorInsertTmp(context, pairs + index, op.Size); - EmitVectorInsertTmp(context, index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - private static void EmitVectorZip(ILEmitterCtx context, int part) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - if (Optimizations.UseSse2) - { - string nameUpk = part == 0 - ? nameof(Sse2.UnpackLow) - : nameof(Sse2.UnpackHigh); - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(op.Size))); - } - else - { - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackLow), GetTypesSflUpk(op.Size))); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); - } - - context.EmitStvec(op.Rd); - } - else - { - int words = op.GetBitsCount() >> 4; - int pairs = words >> op.Size; - - int Base = part != 0 ? pairs : 0; - - for (int index = 0; index < pairs; index++) - { - int idx = index << 1; - - EmitVectorExtractZx(context, op.Rn, Base + index, op.Size); - EmitVectorExtractZx(context, op.Rm, Base + index, op.Size); - - EmitVectorInsertTmp(context, idx + 1, op.Size); - EmitVectorInsertTmp(context, idx, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - } - - private static Type[] GetTypesSflUpk(int size) - { - return new Type[] { VectorIntTypesPerSizeLog2[size], VectorIntTypesPerSizeLog2[size] }; - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSimdShift.cs b/ChocolArm64/Instructions/InstEmitSimdShift.cs deleted file mode 100644 index 6865948a..00000000 --- a/ChocolArm64/Instructions/InstEmitSimdShift.cs +++ /dev/null @@ -1,1175 +0,0 @@ -// https://github.com/intel/ARM_NEON_2_x86_SSE/blob/master/NEON_2_SSE.h - -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -using static ChocolArm64.Instructions.InstEmitSimdHelper; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { -#region "Masks" - private static readonly long[] _masks_RshrnShrn = new long[] - { - 14L << 56 | 12L << 48 | 10L << 40 | 08L << 32 | 06L << 24 | 04L << 16 | 02L << 8 | 00L << 0, - 13L << 56 | 12L << 48 | 09L << 40 | 08L << 32 | 05L << 24 | 04L << 16 | 01L << 8 | 00L << 0, - 11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0 - }; -#endregion - - public static void Rshrn_V(ILEmitterCtx context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], VectorUIntTypesPerSizeLog2[op.Size + 1] }; - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) }; - Type[] typesSfl = new Type[] { typeof(Vector128<sbyte>), typeof(Vector128<sbyte>) }; - Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size + 1] }; - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - - string nameMov = op.RegisterSize == RegisterSize.Simd128 - ? nameof(Sse.MoveLowToHigh) - : nameof(Sse.MoveHighToLow); - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - context.EmitLdvec(op.Rd); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I8(roundConst); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); // value - - context.EmitLdc_I8(_masks_RshrnShrn[op.Size]); // mask - context.Emit(OpCodes.Dup); // mask - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse).GetMethod(nameMov)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorShrImmNarrowOpZx(context, round: true); - } - } - - public static void Shl_S(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - int shift = GetImmShl(op); - - EmitScalarUnaryOpZx(context, () => - { - context.EmitLdc_I4(shift); - - context.Emit(OpCodes.Shl); - }); - } - - public static void Shl_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - int shift = GetImmShl(op); - - if (Optimizations.UseSse2 && op.Size > 0) - { - Type[] typesSll = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorUnaryOpZx(context, () => - { - context.EmitLdc_I4(shift); - - context.Emit(OpCodes.Shl); - }); - } - } - - public static void Shll_V(ILEmitterCtx context) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int shift = 8 << op.Size; - - if (Optimizations.UseSse41) - { - Type[] typesSll = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorShImmWidenBinaryZx(context, () => context.Emit(OpCodes.Shl), shift); - } - } - - public static void Shrn_V(ILEmitterCtx context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) }; - Type[] typesSfl = new Type[] { typeof(Vector128<sbyte>), typeof(Vector128<sbyte>) }; - Type[] typesSve = new Type[] { typeof(long), typeof(long) }; - - string nameMov = op.RegisterSize == RegisterSize.Simd128 - ? nameof(Sse.MoveLowToHigh) - : nameof(Sse.MoveHighToLow); - - int shift = GetImmShr(op); - - context.EmitLdvec(op.Rd); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); // value - - context.EmitLdc_I8(_masks_RshrnShrn[op.Size]); // mask - context.Emit(OpCodes.Dup); // mask - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); - - context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - - context.EmitCall(typeof(Sse).GetMethod(nameMov)); - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorShrImmNarrowOpZx(context, round: false); - } - } - - public static void Sli_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - int shift = GetImmShl(op); - - ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - - context.EmitLdc_I4(shift); - - context.Emit(OpCodes.Shl); - - EmitVectorExtractZx(context, op.Rd, index, op.Size); - - context.EmitLdc_I8((long)mask); - - context.Emit(OpCodes.And); - context.Emit(OpCodes.Or); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Sqrshl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractSx(context, op.Rn, index, op.Size); - EmitVectorExtractSx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_1); - context.EmitLdc_I4(op.Size); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, nameof(SoftFallback.SignedShlRegSatQ)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Sqrshrn_S(ILEmitterCtx context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx); - } - - public static void Sqrshrn_V(ILEmitterCtx context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx); - } - - public static void Sqrshrun_S(ILEmitterCtx context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx); - } - - public static void Sqrshrun_V(ILEmitterCtx context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx); - } - - public static void Sqshl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractSx(context, op.Rn, index, op.Size); - EmitVectorExtractSx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_0); - context.EmitLdc_I4(op.Size); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, nameof(SoftFallback.SignedShlRegSatQ)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Sqshrn_S(ILEmitterCtx context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx); - } - - public static void Sqshrn_V(ILEmitterCtx context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx); - } - - public static void Sqshrun_S(ILEmitterCtx context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx); - } - - public static void Sqshrun_V(ILEmitterCtx context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx); - } - - public static void Srshl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractSx(context, op.Rn, index, op.Size); - EmitVectorExtractSx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_1); - context.EmitLdc_I4(op.Size); - - SoftFallback.EmitCall(context, nameof(SoftFallback.SignedShlReg)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Srshr_S(ILEmitterCtx context) - { - EmitScalarShrImmOpSx(context, ShrImmFlags.Round); - } - - public static void Srshr_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - Type[] typesShs = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(eSize - shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); - - context.EmitLdc_I4(eSize - 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesShs)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorShrImmOpSx(context, ShrImmFlags.Round); - } - } - - public static void Srsra_S(ILEmitterCtx context) - { - EmitScalarShrImmOpSx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - - public static void Srsra_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - Type[] typesShs = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(eSize - shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); - - context.EmitLdc_I4(eSize - 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesShs)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorShrImmOpSx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - } - - public static void Sshl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractSx(context, op.Rn, index, op.Size); - EmitVectorExtractSx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_0); - context.EmitLdc_I4(op.Size); - - SoftFallback.EmitCall(context, nameof(SoftFallback.SignedShlReg)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Sshll_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - int shift = GetImmShl(op); - - if (Optimizations.UseSse41) - { - Type[] typesSll = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - if (shift != 0) - { - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - } - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorShImmWidenBinarySx(context, () => context.Emit(OpCodes.Shl), shift); - } - } - - public static void Sshr_S(ILEmitterCtx context) - { - EmitShrImmOp(context, ShrImmFlags.ScalarSx); - } - - public static void Sshr_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(GetImmShr(op)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitShrImmOp(context, ShrImmFlags.VectorSx); - } - } - - public static void Ssra_S(ILEmitterCtx context) - { - EmitScalarShrImmOpSx(context, ShrImmFlags.Accumulate); - } - - public static void Ssra_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(GetImmShr(op)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorShrImmOpSx(context, ShrImmFlags.Accumulate); - } - } - - public static void Uqrshl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - EmitVectorExtractZx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_1); - context.EmitLdc_I4(op.Size); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, nameof(SoftFallback.UnsignedShlRegSatQ)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Uqrshrn_S(ILEmitterCtx context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx); - } - - public static void Uqrshrn_V(ILEmitterCtx context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx); - } - - public static void Uqshl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - EmitVectorExtractZx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_0); - context.EmitLdc_I4(op.Size); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - SoftFallback.EmitCall(context, nameof(SoftFallback.UnsignedShlRegSatQ)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Uqshrn_S(ILEmitterCtx context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx); - } - - public static void Uqshrn_V(ILEmitterCtx context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx); - } - - public static void Urshl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - EmitVectorExtractZx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_1); - context.EmitLdc_I4(op.Size); - - SoftFallback.EmitCall(context, nameof(SoftFallback.UnsignedShlReg)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Urshr_S(ILEmitterCtx context) - { - EmitScalarShrImmOpZx(context, ShrImmFlags.Round); - } - - public static void Urshr_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Type[] typesShs = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(eSize - shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); - - context.EmitLdc_I4(eSize - 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorShrImmOpZx(context, ShrImmFlags.Round); - } - } - - public static void Ursra_S(ILEmitterCtx context) - { - EmitScalarShrImmOpZx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - - public static void Ursra_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Type[] typesShs = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(eSize - shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); - - context.EmitLdc_I4(eSize - 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorShrImmOpZx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - } - - public static void Ushl_V(ILEmitterCtx context) - { - OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> op.Size; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size); - EmitVectorExtractZx(context, op.Rm, index, op.Size); - - context.Emit(OpCodes.Ldc_I4_0); - context.EmitLdc_I4(op.Size); - - SoftFallback.EmitCall(context, nameof(SoftFallback.UnsignedShlReg)); - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - public static void Ushll_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - int shift = GetImmShl(op); - - if (Optimizations.UseSse41) - { - Type[] typesSll = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) }; - Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; - - string[] namesCvt = new string[] { nameof(Sse41.ConvertToVector128Int16), - nameof(Sse41.ConvertToVector128Int32), - nameof(Sse41.ConvertToVector128Int64) }; - - context.EmitLdvec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - context.Emit(OpCodes.Ldc_I4_8); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); - } - - context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - - if (shift != 0) - { - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - } - - context.EmitStvec(op.Rd); - } - else - { - EmitVectorShImmWidenBinaryZx(context, () => context.Emit(OpCodes.Shl), shift); - } - } - - public static void Ushr_S(ILEmitterCtx context) - { - EmitShrImmOp(context, ShrImmFlags.ScalarZx); - } - - public static void Ushr_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(GetImmShr(op)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitShrImmOp(context, ShrImmFlags.VectorZx); - } - } - - public static void Usra_S(ILEmitterCtx context) - { - EmitScalarShrImmOpZx(context, ShrImmFlags.Accumulate); - } - - public static void Usra_V(ILEmitterCtx context) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - - context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - - context.EmitLdc_I4(GetImmShr(op)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - else - { - EmitVectorShrImmOpZx(context, ShrImmFlags.Accumulate); - } - } - - [Flags] - private enum ShrImmFlags - { - Scalar = 1 << 0, - Signed = 1 << 1, - - Round = 1 << 2, - Accumulate = 1 << 3, - - ScalarSx = Scalar | Signed, - ScalarZx = Scalar, - - VectorSx = Signed, - VectorZx = 0 - } - - private static void EmitScalarShrImmOpSx(ILEmitterCtx context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.ScalarSx | flags); - } - - private static void EmitScalarShrImmOpZx(ILEmitterCtx context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.ScalarZx | flags); - } - - private static void EmitVectorShrImmOpSx(ILEmitterCtx context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.VectorSx | flags); - } - - private static void EmitVectorShrImmOpZx(ILEmitterCtx context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.VectorZx | flags); - } - - private static void EmitShrImmOp(ILEmitterCtx context, ShrImmFlags flags) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - bool scalar = (flags & ShrImmFlags.Scalar) != 0; - bool signed = (flags & ShrImmFlags.Signed) != 0; - bool round = (flags & ShrImmFlags.Round) != 0; - bool accumulate = (flags & ShrImmFlags.Accumulate) != 0; - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - int bytes = op.GetBitsCount() >> 3; - int elems = !scalar ? bytes >> op.Size : 1; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size, signed); - - if (op.Size <= 2) - { - if (round) - { - context.EmitLdc_I8(roundConst); - - context.Emit(OpCodes.Add); - } - - context.EmitLdc_I4(shift); - - context.Emit(signed ? OpCodes.Shr : OpCodes.Shr_Un); - } - else /* if (op.Size == 3) */ - { - EmitShrImm64(context, signed, round ? roundConst : 0L, shift); - } - - if (accumulate) - { - EmitVectorExtract(context, op.Rd, index, op.Size, signed); - - context.Emit(OpCodes.Add); - } - - EmitVectorInsert(context, op.Rd, index, op.Size); - } - - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - private static void EmitVectorShrImmNarrowOpZx(ILEmitterCtx context, bool round) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - if (part != 0) - { - context.EmitLdvec(op.Rd); - context.EmitStvectmp(); - } - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractZx(context, op.Rn, index, op.Size + 1); - - if (round) - { - context.EmitLdc_I8(roundConst); - - context.Emit(OpCodes.Add); - } - - context.EmitLdc_I4(shift); - - context.Emit(OpCodes.Shr_Un); - - EmitVectorInsertTmp(context, part + index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (part == 0) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - [Flags] - private enum ShrImmSaturatingNarrowFlags - { - Scalar = 1 << 0, - SignedSrc = 1 << 1, - SignedDst = 1 << 2, - - Round = 1 << 3, - - ScalarSxSx = Scalar | SignedSrc | SignedDst, - ScalarSxZx = Scalar | SignedSrc, - ScalarZxZx = Scalar, - - VectorSxSx = SignedSrc | SignedDst, - VectorSxZx = SignedSrc, - VectorZxZx = 0 - } - - private static void EmitRoundShrImmSaturatingNarrowOp(ILEmitterCtx context, ShrImmSaturatingNarrowFlags flags) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.Round | flags); - } - - private static void EmitShrImmSaturatingNarrowOp(ILEmitterCtx context, ShrImmSaturatingNarrowFlags flags) - { - OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - - bool scalar = (flags & ShrImmSaturatingNarrowFlags.Scalar) != 0; - bool signedSrc = (flags & ShrImmSaturatingNarrowFlags.SignedSrc) != 0; - bool signedDst = (flags & ShrImmSaturatingNarrowFlags.SignedDst) != 0; - bool round = (flags & ShrImmSaturatingNarrowFlags.Round) != 0; - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - int elems = !scalar ? 8 >> op.Size : 1; - - int part = !scalar && (op.RegisterSize == RegisterSize.Simd128) ? elems : 0; - - if (scalar) - { - EmitVectorZeroLowerTmp(context); - } - - if (part != 0) - { - context.EmitLdvec(op.Rd); - context.EmitStvectmp(); - } - - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, index, op.Size + 1, signedSrc); - - if (op.Size <= 1 || !round) - { - if (round) - { - context.EmitLdc_I8(roundConst); - - context.Emit(OpCodes.Add); - } - - context.EmitLdc_I4(shift); - - context.Emit(signedSrc ? OpCodes.Shr : OpCodes.Shr_Un); - } - else /* if (op.Size == 2 && round) */ - { - EmitShrImm64(context, signedSrc, roundConst, shift); // shift <= 32 - } - - EmitSatQ(context, op.Size, signedSrc, signedDst); - - EmitVectorInsertTmp(context, part + index, op.Size); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if (part == 0) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - - // dst64 = (Int(src64, signed) + roundConst) >> shift; - private static void EmitShrImm64(ILEmitterCtx context, bool signed, long roundConst, int shift) - { - context.EmitLdc_I8(roundConst); - context.EmitLdc_I4(shift); - - SoftFallback.EmitCall(context, signed - ? nameof(SoftFallback.SignedShrImm64) - : nameof(SoftFallback.UnsignedShrImm64)); - } - - private static void EmitVectorShImmWidenBinarySx(ILEmitterCtx context, Action emit, int imm) - { - EmitVectorShImmWidenBinaryOp(context, emit, imm, true); - } - - private static void EmitVectorShImmWidenBinaryZx(ILEmitterCtx context, Action emit, int imm) - { - EmitVectorShImmWidenBinaryOp(context, emit, imm, false); - } - - private static void EmitVectorShImmWidenBinaryOp(ILEmitterCtx context, Action emit, int imm, bool signed) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtract(context, op.Rn, part + index, op.Size, signed); - - context.EmitLdc_I4(imm); - - emit(); - - EmitVectorInsertTmp(context, index, op.Size + 1); - } - - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitSystem.cs b/ChocolArm64/Instructions/InstEmitSystem.cs deleted file mode 100644 index ac264de9..00000000 --- a/ChocolArm64/Instructions/InstEmitSystem.cs +++ /dev/null @@ -1,137 +0,0 @@ -using ChocolArm64.Decoders; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64.Instructions -{ - static partial class InstEmit - { - public static void Hint(ILEmitterCtx context) - { - // Execute as no-op. - } - - public static void Isb(ILEmitterCtx context) - { - // Execute as no-op. - } - - public static void Mrs(ILEmitterCtx context) - { - OpCodeSystem64 op = (OpCodeSystem64)context.CurrOp; - - context.EmitLdarg(TranslatedSub.StateArgIdx); - - string propName; - - switch (GetPackedId(op)) - { - case 0b11_011_0000_0000_001: propName = nameof(CpuThreadState.CtrEl0); break; - case 0b11_011_0000_0000_111: propName = nameof(CpuThreadState.DczidEl0); break; - case 0b11_011_0100_0100_000: propName = nameof(CpuThreadState.CFpcr); break; - case 0b11_011_0100_0100_001: propName = nameof(CpuThreadState.CFpsr); break; - case 0b11_011_1101_0000_010: propName = nameof(CpuThreadState.TpidrEl0); break; - case 0b11_011_1101_0000_011: propName = nameof(CpuThreadState.Tpidr); break; - case 0b11_011_1110_0000_000: propName = nameof(CpuThreadState.CntfrqEl0); break; - case 0b11_011_1110_0000_001: propName = nameof(CpuThreadState.CntpctEl0); break; - - default: throw new NotImplementedException($"Unknown MRS at {op.Position:x16}"); - } - - context.EmitCallPropGet(typeof(CpuThreadState), propName); - - PropertyInfo propInfo = typeof(CpuThreadState).GetProperty(propName); - - if (propInfo.PropertyType != typeof(long) && - propInfo.PropertyType != typeof(ulong)) - { - context.Emit(OpCodes.Conv_U8); - } - - context.EmitStintzr(op.Rt); - } - - public static void Msr(ILEmitterCtx context) - { - OpCodeSystem64 op = (OpCodeSystem64)context.CurrOp; - - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdintzr(op.Rt); - - string propName; - - switch (GetPackedId(op)) - { - case 0b11_011_0100_0100_000: propName = nameof(CpuThreadState.CFpcr); break; - case 0b11_011_0100_0100_001: propName = nameof(CpuThreadState.CFpsr); break; - case 0b11_011_1101_0000_010: propName = nameof(CpuThreadState.TpidrEl0); break; - - default: throw new NotImplementedException($"Unknown MSR at {op.Position:x16}"); - } - - PropertyInfo propInfo = typeof(CpuThreadState).GetProperty(propName); - - if (propInfo.PropertyType != typeof(long) && - propInfo.PropertyType != typeof(ulong)) - { - context.Emit(OpCodes.Conv_U4); - } - - context.EmitCallPropSet(typeof(CpuThreadState), propName); - } - - public static void Nop(ILEmitterCtx context) - { - // Do nothing. - } - - public static void Sys(ILEmitterCtx context) - { - // This instruction is used to do some operations on the CPU like cache invalidation, - // address translation and the like. - // We treat it as no-op here since we don't have any cache being emulated anyway. - OpCodeSystem64 op = (OpCodeSystem64)context.CurrOp; - - switch (GetPackedId(op)) - { - case 0b11_011_0111_0100_001: - { - // DC ZVA - for (int offs = 0; offs < (4 << CpuThreadState.DczSizeLog2); offs += 8) - { - context.EmitLdintzr(op.Rt); - context.EmitLdc_I(offs); - - context.Emit(OpCodes.Add); - - context.EmitLdc_I8(0); - - InstEmitMemoryHelper.EmitWriteCall(context, 3); - } - - break; - } - - // No-op - case 0b11_011_0111_1110_001: //DC CIVAC - break; - } - } - - private static int GetPackedId(OpCodeSystem64 op) - { - int id; - - id = op.Op2 << 0; - id |= op.CRm << 3; - id |= op.CRn << 7; - id |= op.Op1 << 11; - id |= op.Op0 << 14; - - return id; - } - } -} diff --git a/ChocolArm64/Instructions/InstEmitter.cs b/ChocolArm64/Instructions/InstEmitter.cs deleted file mode 100644 index db6e8604..00000000 --- a/ChocolArm64/Instructions/InstEmitter.cs +++ /dev/null @@ -1,6 +0,0 @@ -using ChocolArm64.Translation; - -namespace ChocolArm64.Instructions -{ - delegate void InstEmitter(ILEmitterCtx context); -}
\ No newline at end of file diff --git a/ChocolArm64/Instructions/SoftFallback.cs b/ChocolArm64/Instructions/SoftFallback.cs deleted file mode 100644 index 16638894..00000000 --- a/ChocolArm64/Instructions/SoftFallback.cs +++ /dev/null @@ -1,1194 +0,0 @@ -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Runtime.CompilerServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace ChocolArm64.Instructions -{ - using static VectorHelper; - - static class SoftFallback - { - public static void EmitCall(ILEmitterCtx context, string mthdName) - { - context.EmitCall(typeof(SoftFallback), mthdName); - } - -#region "ShlReg" - public static long SignedShlReg(long value, long shift, bool round, int size) - { - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return SignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return 0L; - } - - return value << shiftLsB; - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - public static ulong UnsignedShlReg(ulong value, ulong shift, bool round, int size) - { - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return UnsignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return 0UL; - } - - return value << shiftLsB; - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - public static long SignedShlRegSatQ(long value, long shift, bool round, int size, CpuThreadState state) - { - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return SignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return SignedSignSatQ(value, eSize, state); - } - - if (eSize == 64) - { - long shl = value << shiftLsB; - long shr = shl >> shiftLsB; - - if (shr != value) - { - return SignedSignSatQ(value, eSize, state); - } - else /* if (shr == value) */ - { - return shl; - } - } - else /* if (eSize != 64) */ - { - return SignedSrcSignedDstSatQ(value << shiftLsB, size, state); - } - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - public static ulong UnsignedShlRegSatQ(ulong value, ulong shift, bool round, int size, CpuThreadState state) - { - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return UnsignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return UnsignedSignSatQ(value, eSize, state); - } - - if (eSize == 64) - { - ulong shl = value << shiftLsB; - ulong shr = shl >> shiftLsB; - - if (shr != value) - { - return UnsignedSignSatQ(value, eSize, state); - } - else /* if (shr == value) */ - { - return shl; - } - } - else /* if (eSize != 64) */ - { - return UnsignedSrcUnsignedDstSatQ(value << shiftLsB, size, state); - } - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - private static long SignedShrReg(long value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}. - { - if (round) - { - if (shift >= eSize) - { - return 0L; - } - - long roundConst = 1L << (shift - 1); - - long add = value + roundConst; - - if (eSize == 64) - { - if ((~value & (value ^ add)) < 0L) - { - return (long)((ulong)add >> shift); - } - else - { - return add >> shift; - } - } - else /* if (eSize != 64) */ - { - return add >> shift; - } - } - else /* if (!round) */ - { - if (shift >= eSize) - { - if (value < 0L) - { - return -1L; - } - else /* if (value >= 0L) */ - { - return 0L; - } - } - - return value >> shift; - } - } - - private static ulong UnsignedShrReg(ulong value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}. - { - if (round) - { - if (shift > 64) - { - return 0UL; - } - - ulong roundConst = 1UL << (shift - 1); - - ulong add = value + roundConst; - - if (eSize == 64) - { - if ((add < value) && (add < roundConst)) - { - if (shift == 64) - { - return 1UL; - } - - return (add >> shift) | (0x8000000000000000UL >> (shift - 1)); - } - else - { - if (shift == 64) - { - return 0UL; - } - - return add >> shift; - } - } - else /* if (eSize != 64) */ - { - if (shift == 64) - { - return 0UL; - } - - return add >> shift; - } - } - else /* if (!round) */ - { - if (shift >= eSize) - { - return 0UL; - } - - return value >> shift; - } - } - - private static long SignedSignSatQ(long op, int eSize, CpuThreadState state) // eSize := {8, 16, 32, 64}. - { - long tMaxValue = (1L << (eSize - 1)) - 1L; - long tMinValue = -(1L << (eSize - 1)); - - if (op > 0L) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMaxValue; - } - else if (op < 0L) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMinValue; - } - else - { - return 0L; - } - } - - private static ulong UnsignedSignSatQ(ulong op, int eSize, CpuThreadState state) // eSize := {8, 16, 32, 64}. - { - ulong tMaxValue = ulong.MaxValue >> (64 - eSize); - - if (op > 0UL) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMaxValue; - } - else - { - return 0UL; - } - } -#endregion - -#region "ShrImm64" - public static long SignedShrImm64(long value, long roundConst, int shift) - { - if (roundConst == 0L) - { - if (shift <= 63) - { - return value >> shift; - } - else /* if (shift == 64) */ - { - if (value < 0L) - { - return -1L; - } - else /* if (value >= 0L) */ - { - return 0L; - } - } - } - else /* if (roundConst == 1L << (shift - 1)) */ - { - if (shift <= 63) - { - long add = value + roundConst; - - if ((~value & (value ^ add)) < 0L) - { - return (long)((ulong)add >> shift); - } - else - { - return add >> shift; - } - } - else /* if (shift == 64) */ - { - return 0L; - } - } - } - - public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift) - { - if (roundConst == 0L) - { - if (shift <= 63) - { - return value >> shift; - } - else /* if (shift == 64) */ - { - return 0UL; - } - } - else /* if (roundConst == 1L << (shift - 1)) */ - { - ulong add = value + (ulong)roundConst; - - if ((add < value) && (add < (ulong)roundConst)) - { - if (shift <= 63) - { - return (add >> shift) | (0x8000000000000000UL >> (shift - 1)); - } - else /* if (shift == 64) */ - { - return 1UL; - } - } - else - { - if (shift <= 63) - { - return add >> shift; - } - else /* if (shift == 64) */ - { - return 0UL; - } - } - } - } -#endregion - -#region "Saturating" - public static long SignedSrcSignedDstSatQ(long op, int size, CpuThreadState state) - { - int eSize = 8 << size; - - long tMaxValue = (1L << (eSize - 1)) - 1L; - long tMinValue = -(1L << (eSize - 1)); - - if (op > tMaxValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMaxValue; - } - else if (op < tMinValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMinValue; - } - else - { - return op; - } - } - - public static ulong SignedSrcUnsignedDstSatQ(long op, int size, CpuThreadState state) - { - int eSize = 8 << size; - - ulong tMaxValue = (1UL << eSize) - 1UL; - ulong tMinValue = 0UL; - - if (op > (long)tMaxValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMaxValue; - } - else if (op < (long)tMinValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMinValue; - } - else - { - return (ulong)op; - } - } - - public static long UnsignedSrcSignedDstSatQ(ulong op, int size, CpuThreadState state) - { - int eSize = 8 << size; - - long tMaxValue = (1L << (eSize - 1)) - 1L; - - if (op > (ulong)tMaxValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMaxValue; - } - else - { - return (long)op; - } - } - - public static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size, CpuThreadState state) - { - int eSize = 8 << size; - - ulong tMaxValue = (1UL << eSize) - 1UL; - - if (op > tMaxValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return tMaxValue; - } - else - { - return op; - } - } - - public static long UnarySignedSatQAbsOrNeg(long op, CpuThreadState state) - { - if (op == long.MinValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return long.MaxValue; - } - else - { - return op; - } - } - - public static long BinarySignedSatQAdd(long op1, long op2, CpuThreadState state) - { - long add = op1 + op2; - - if ((~(op1 ^ op2) & (op1 ^ add)) < 0L) - { - state.SetFpsrFlag(Fpsr.Qc); - - if (op1 < 0L) - { - return long.MinValue; - } - else - { - return long.MaxValue; - } - } - else - { - return add; - } - } - - public static ulong BinaryUnsignedSatQAdd(ulong op1, ulong op2, CpuThreadState state) - { - ulong add = op1 + op2; - - if ((add < op1) && (add < op2)) - { - state.SetFpsrFlag(Fpsr.Qc); - - return ulong.MaxValue; - } - else - { - return add; - } - } - - public static long BinarySignedSatQSub(long op1, long op2, CpuThreadState state) - { - long sub = op1 - op2; - - if (((op1 ^ op2) & (op1 ^ sub)) < 0L) - { - state.SetFpsrFlag(Fpsr.Qc); - - if (op1 < 0L) - { - return long.MinValue; - } - else - { - return long.MaxValue; - } - } - else - { - return sub; - } - } - - public static ulong BinaryUnsignedSatQSub(ulong op1, ulong op2, CpuThreadState state) - { - ulong sub = op1 - op2; - - if (op1 < op2) - { - state.SetFpsrFlag(Fpsr.Qc); - - return ulong.MinValue; - } - else - { - return sub; - } - } - - public static long BinarySignedSatQAcc(ulong op1, long op2, CpuThreadState state) - { - if (op1 <= (ulong)long.MaxValue) - { - // op1 from ulong.MinValue to (ulong)long.MaxValue - // op2 from long.MinValue to long.MaxValue - - long add = (long)op1 + op2; - - if ((~op2 & add) < 0L) - { - state.SetFpsrFlag(Fpsr.Qc); - - return long.MaxValue; - } - else - { - return add; - } - } - else if (op2 >= 0L) - { - // op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue - // op2 from (long)ulong.MinValue to long.MaxValue - - state.SetFpsrFlag(Fpsr.Qc); - - return long.MaxValue; - } - else - { - // op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue - // op2 from long.MinValue to (long)ulong.MinValue - 1L - - ulong add = op1 + (ulong)op2; - - if (add > (ulong)long.MaxValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return long.MaxValue; - } - else - { - return (long)add; - } - } - } - - public static ulong BinaryUnsignedSatQAcc(long op1, ulong op2, CpuThreadState state) - { - if (op1 >= 0L) - { - // op1 from (long)ulong.MinValue to long.MaxValue - // op2 from ulong.MinValue to ulong.MaxValue - - ulong add = (ulong)op1 + op2; - - if ((add < (ulong)op1) && (add < op2)) - { - state.SetFpsrFlag(Fpsr.Qc); - - return ulong.MaxValue; - } - else - { - return add; - } - } - else if (op2 > (ulong)long.MaxValue) - { - // op1 from long.MinValue to (long)ulong.MinValue - 1L - // op2 from (ulong)long.MaxValue + 1UL to ulong.MaxValue - - return (ulong)op1 + op2; - } - else - { - // op1 from long.MinValue to (long)ulong.MinValue - 1L - // op2 from ulong.MinValue to (ulong)long.MaxValue - - long add = op1 + (long)op2; - - if (add < (long)ulong.MinValue) - { - state.SetFpsrFlag(Fpsr.Qc); - - return ulong.MinValue; - } - else - { - return (ulong)add; - } - } - } -#endregion - -#region "Count" - public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). - { - value ^= value >> 1; - - int highBit = size - 2; - - for (int bit = highBit; bit >= 0; bit--) - { - if (((int)(value >> bit) & 0b1) != 0) - { - return (ulong)(highBit - bit); - } - } - - return (ulong)(size - 1); - } - - private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; - - public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). - { - if (value == 0ul) - { - return (ulong)size; - } - - int nibbleIdx = size; - int preCount, count = 0; - - do - { - nibbleIdx -= 4; - preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111]; - count += preCount; - } - while (preCount == 4); - - return (ulong)count; - } - - public static ulong CountSetBits8(ulong value) // "size" is 8 (SIMD&FP Inst.). - { - value = ((value >> 1) & 0x55ul) + (value & 0x55ul); - value = ((value >> 2) & 0x33ul) + (value & 0x33ul); - - return (value >> 4) + (value & 0x0ful); - } -#endregion - -#region "Crc32" - private const uint Crc32RevPoly = 0xedb88320; - private const uint Crc32CRevPoly = 0x82f63b78; - - public static uint Crc32B(uint crc, byte val) => Crc32 (crc, Crc32RevPoly, val); - public static uint Crc32H(uint crc, ushort val) => Crc32H(crc, Crc32RevPoly, val); - public static uint Crc32W(uint crc, uint val) => Crc32W(crc, Crc32RevPoly, val); - public static uint Crc32X(uint crc, ulong val) => Crc32X(crc, Crc32RevPoly, val); - - public static uint Crc32Cb(uint crc, byte val) => Crc32 (crc, Crc32CRevPoly, val); - public static uint Crc32Ch(uint crc, ushort val) => Crc32H(crc, Crc32CRevPoly, val); - public static uint Crc32Cw(uint crc, uint val) => Crc32W(crc, Crc32CRevPoly, val); - public static uint Crc32Cx(uint crc, ulong val) => Crc32X(crc, Crc32CRevPoly, val); - - private static uint Crc32H(uint crc, uint poly, ushort val) - { - crc = Crc32(crc, poly, (byte)(val >> 0)); - crc = Crc32(crc, poly, (byte)(val >> 8)); - - return crc; - } - - private static uint Crc32W(uint crc, uint poly, uint val) - { - crc = Crc32(crc, poly, (byte)(val >> 0 )); - crc = Crc32(crc, poly, (byte)(val >> 8 )); - crc = Crc32(crc, poly, (byte)(val >> 16)); - crc = Crc32(crc, poly, (byte)(val >> 24)); - - return crc; - } - - private static uint Crc32X(uint crc, uint poly, ulong val) - { - crc = Crc32(crc, poly, (byte)(val >> 0 )); - crc = Crc32(crc, poly, (byte)(val >> 8 )); - crc = Crc32(crc, poly, (byte)(val >> 16)); - crc = Crc32(crc, poly, (byte)(val >> 24)); - crc = Crc32(crc, poly, (byte)(val >> 32)); - crc = Crc32(crc, poly, (byte)(val >> 40)); - crc = Crc32(crc, poly, (byte)(val >> 48)); - crc = Crc32(crc, poly, (byte)(val >> 56)); - - return crc; - } - - private static uint Crc32(uint crc, uint poly, byte val) - { - crc ^= val; - - for (int bit = 7; bit >= 0; bit--) - { - uint mask = (uint)(-(int)(crc & 1)); - - crc = (crc >> 1) ^ (poly & mask); - } - - return crc; - } -#endregion - -#region "Aes" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> Decrypt(Vector128<float> value, Vector128<float> roundKey) - { - if (!Sse.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(Sse.Xor(value, roundKey))); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> Encrypt(Vector128<float> value, Vector128<float> roundKey) - { - if (!Sse.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(Sse.Xor(value, roundKey))); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> InverseMixColumns(Vector128<float> value) - { - return CryptoHelper.AesInvMixColumns(value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> MixColumns(Vector128<float> value) - { - return CryptoHelper.AesMixColumns(value); - } -#endregion - -#region "Sha1" - public static Vector128<float> HashChoose(Vector128<float> hash_abcd, uint hash_e, Vector128<float> wk) - { - for (int e = 0; e <= 3; e++) - { - uint t = ShaChoose((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), - (uint)VectorExtractIntZx(hash_abcd, (byte)2, 2), - (uint)VectorExtractIntZx(hash_abcd, (byte)3, 2)); - - hash_e += Rol((uint)VectorExtractIntZx(hash_abcd, (byte)0, 2), 5) + t; - hash_e += (uint)VectorExtractIntZx(wk, (byte)e, 2); - - t = Rol((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), 30); - hash_abcd = VectorInsertInt((ulong)t, hash_abcd, (byte)1, 2); - - Rol32_160(ref hash_e, ref hash_abcd); - } - - return hash_abcd; - } - - public static uint FixedRotate(uint hash_e) - { - return hash_e.Rol(30); - } - - public static Vector128<float> HashMajority(Vector128<float> hash_abcd, uint hash_e, Vector128<float> wk) - { - for (int e = 0; e <= 3; e++) - { - uint t = ShaMajority((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), - (uint)VectorExtractIntZx(hash_abcd, (byte)2, 2), - (uint)VectorExtractIntZx(hash_abcd, (byte)3, 2)); - - hash_e += Rol((uint)VectorExtractIntZx(hash_abcd, (byte)0, 2), 5) + t; - hash_e += (uint)VectorExtractIntZx(wk, (byte)e, 2); - - t = Rol((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), 30); - hash_abcd = VectorInsertInt((ulong)t, hash_abcd, (byte)1, 2); - - Rol32_160(ref hash_e, ref hash_abcd); - } - - return hash_abcd; - } - - public static Vector128<float> HashParity(Vector128<float> hash_abcd, uint hash_e, Vector128<float> wk) - { - for (int e = 0; e <= 3; e++) - { - uint t = ShaParity((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), - (uint)VectorExtractIntZx(hash_abcd, (byte)2, 2), - (uint)VectorExtractIntZx(hash_abcd, (byte)3, 2)); - - hash_e += Rol((uint)VectorExtractIntZx(hash_abcd, (byte)0, 2), 5) + t; - hash_e += (uint)VectorExtractIntZx(wk, (byte)e, 2); - - t = Rol((uint)VectorExtractIntZx(hash_abcd, (byte)1, 2), 30); - hash_abcd = VectorInsertInt((ulong)t, hash_abcd, (byte)1, 2); - - Rol32_160(ref hash_e, ref hash_abcd); - } - - return hash_abcd; - } - - public static Vector128<float> Sha1SchedulePart1(Vector128<float> w0_3, Vector128<float> w4_7, Vector128<float> w8_11) - { - if (!Sse.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - Vector128<float> result = new Vector128<float>(); - - ulong t2 = VectorExtractIntZx(w4_7, (byte)0, 3); - ulong t1 = VectorExtractIntZx(w0_3, (byte)1, 3); - - result = VectorInsertInt((ulong)t1, result, (byte)0, 3); - result = VectorInsertInt((ulong)t2, result, (byte)1, 3); - - return Sse.Xor(result, Sse.Xor(w0_3, w8_11)); - } - - public static Vector128<float> Sha1SchedulePart2(Vector128<float> tw0_3, Vector128<float> w12_15) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - Vector128<float> result = new Vector128<float>(); - - Vector128<float> t = Sse.Xor(tw0_3, Sse.StaticCast<uint, float>( - Sse2.ShiftRightLogical128BitLane(Sse.StaticCast<float, uint>(w12_15), (byte)4))); - - uint tE0 = (uint)VectorExtractIntZx(t, (byte)0, 2); - uint tE1 = (uint)VectorExtractIntZx(t, (byte)1, 2); - uint tE2 = (uint)VectorExtractIntZx(t, (byte)2, 2); - uint tE3 = (uint)VectorExtractIntZx(t, (byte)3, 2); - - result = VectorInsertInt((ulong)tE0.Rol(1), result, (byte)0, 2); - result = VectorInsertInt((ulong)tE1.Rol(1), result, (byte)1, 2); - result = VectorInsertInt((ulong)tE2.Rol(1), result, (byte)2, 2); - - return VectorInsertInt((ulong)(tE3.Rol(1) ^ tE0.Rol(2)), result, (byte)3, 2); - } - - private static void Rol32_160(ref uint y, ref Vector128<float> x) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - uint xE3 = (uint)VectorExtractIntZx(x, (byte)3, 2); - - x = Sse.StaticCast<uint, float>(Sse2.ShiftLeftLogical128BitLane(Sse.StaticCast<float, uint>(x), (byte)4)); - x = VectorInsertInt((ulong)y, x, (byte)0, 2); - - y = xE3; - } - - private static uint ShaChoose(uint x, uint y, uint z) - { - return ((y ^ z) & x) ^ z; - } - - private static uint ShaMajority(uint x, uint y, uint z) - { - return (x & y) | ((x | y) & z); - } - - private static uint ShaParity(uint x, uint y, uint z) - { - return x ^ y ^ z; - } - - private static uint Rol(this uint value, int count) - { - return (value << count) | (value >> (32 - count)); - } -#endregion - -#region "Sha256" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> HashLower(Vector128<float> hash_abcd, Vector128<float> hash_efgh, Vector128<float> wk) - { - return Sha256Hash(hash_abcd, hash_efgh, wk, true); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> HashUpper(Vector128<float> hash_efgh, Vector128<float> hash_abcd, Vector128<float> wk) - { - return Sha256Hash(hash_abcd, hash_efgh, wk, false); - } - - public static Vector128<float> Sha256SchedulePart1(Vector128<float> w0_3, Vector128<float> w4_7) - { - Vector128<float> result = new Vector128<float>(); - - for (int e = 0; e <= 3; e++) - { - uint elt = (uint)VectorExtractIntZx(e <= 2 ? w0_3 : w4_7, (byte)(e <= 2 ? e + 1 : 0), 2); - - elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3); - - elt += (uint)VectorExtractIntZx(w0_3, (byte)e, 2); - - result = VectorInsertInt((ulong)elt, result, (byte)e, 2); - } - - return result; - } - - public static Vector128<float> Sha256SchedulePart2(Vector128<float> w0_3, Vector128<float> w8_11, Vector128<float> w12_15) - { - Vector128<float> result = new Vector128<float>(); - - ulong t1 = VectorExtractIntZx(w12_15, (byte)1, 3); - - for (int e = 0; e <= 1; e++) - { - uint elt = t1.ULongPart(e); - - elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10); - - elt += (uint)VectorExtractIntZx(w0_3, (byte)e, 2); - elt += (uint)VectorExtractIntZx(w8_11, (byte)(e + 1), 2); - - result = VectorInsertInt((ulong)elt, result, (byte)e, 2); - } - - t1 = VectorExtractIntZx(result, (byte)0, 3); - - for (int e = 2; e <= 3; e++) - { - uint elt = t1.ULongPart(e - 2); - - elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10); - - elt += (uint)VectorExtractIntZx(w0_3, (byte)e, 2); - elt += (uint)VectorExtractIntZx(e == 2 ? w8_11 : w12_15, (byte)(e == 2 ? 3 : 0), 2); - - result = VectorInsertInt((ulong)elt, result, (byte)e, 2); - } - - return result; - } - - private static Vector128<float> Sha256Hash(Vector128<float> x, Vector128<float> y, Vector128<float> w, bool part1) - { - for (int e = 0; e <= 3; e++) - { - uint chs = ShaChoose((uint)VectorExtractIntZx(y, (byte)0, 2), - (uint)VectorExtractIntZx(y, (byte)1, 2), - (uint)VectorExtractIntZx(y, (byte)2, 2)); - - uint maj = ShaMajority((uint)VectorExtractIntZx(x, (byte)0, 2), - (uint)VectorExtractIntZx(x, (byte)1, 2), - (uint)VectorExtractIntZx(x, (byte)2, 2)); - - uint t1 = (uint)VectorExtractIntZx(y, (byte)3, 2); - t1 += ShaHashSigma1((uint)VectorExtractIntZx(y, (byte)0, 2)) + chs; - t1 += (uint)VectorExtractIntZx(w, (byte)e, 2); - - uint t2 = t1 + (uint)VectorExtractIntZx(x, (byte)3, 2); - x = VectorInsertInt((ulong)t2, x, (byte)3, 2); - t2 = t1 + ShaHashSigma0((uint)VectorExtractIntZx(x, (byte)0, 2)) + maj; - y = VectorInsertInt((ulong)t2, y, (byte)3, 2); - - Rol32_256(ref y, ref x); - } - - return part1 ? x : y; - } - - private static void Rol32_256(ref Vector128<float> y, ref Vector128<float> x) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - uint yE3 = (uint)VectorExtractIntZx(y, (byte)3, 2); - uint xE3 = (uint)VectorExtractIntZx(x, (byte)3, 2); - - y = Sse.StaticCast<uint, float>(Sse2.ShiftLeftLogical128BitLane(Sse.StaticCast<float, uint>(y), (byte)4)); - x = Sse.StaticCast<uint, float>(Sse2.ShiftLeftLogical128BitLane(Sse.StaticCast<float, uint>(x), (byte)4)); - - y = VectorInsertInt((ulong)xE3, y, (byte)0, 2); - x = VectorInsertInt((ulong)yE3, x, (byte)0, 2); - } - - private static uint ShaHashSigma0(uint x) - { - return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22); - } - - private static uint ShaHashSigma1(uint x) - { - return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25); - } - - private static uint Ror(this uint value, int count) - { - return (value >> count) | (value << (32 - count)); - } - - private static uint Lsr(this uint value, int count) - { - return value >> count; - } - - private static uint ULongPart(this ulong value, int part) - { - return part == 0 - ? (uint)(value & 0xFFFFFFFFUL) - : (uint)(value >> 32); - } -#endregion - -#region "Reverse" - public static uint ReverseBits8(uint value) - { - value = ((value & 0xaa) >> 1) | ((value & 0x55) << 1); - value = ((value & 0xcc) >> 2) | ((value & 0x33) << 2); - - return (value >> 4) | ((value & 0x0f) << 4); - } - - public static uint ReverseBits32(uint value) - { - value = ((value & 0xaaaaaaaa) >> 1) | ((value & 0x55555555) << 1); - value = ((value & 0xcccccccc) >> 2) | ((value & 0x33333333) << 2); - value = ((value & 0xf0f0f0f0) >> 4) | ((value & 0x0f0f0f0f) << 4); - value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8); - - return (value >> 16) | (value << 16); - } - - public static ulong ReverseBits64(ulong value) - { - value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1 ) | ((value & 0x5555555555555555) << 1 ); - value = ((value & 0xcccccccccccccccc) >> 2 ) | ((value & 0x3333333333333333) << 2 ); - value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4 ) | ((value & 0x0f0f0f0f0f0f0f0f) << 4 ); - value = ((value & 0xff00ff00ff00ff00) >> 8 ) | ((value & 0x00ff00ff00ff00ff) << 8 ); - value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16); - - return (value >> 32) | (value << 32); - } - - public static uint ReverseBytes16_32(uint value) => (uint)ReverseBytes16_64(value); - public static uint ReverseBytes32_32(uint value) => (uint)ReverseBytes32_64(value); - - public static ulong ReverseBytes16_64(ulong value) => ReverseBytes(value, RevSize.Rev16); - public static ulong ReverseBytes32_64(ulong value) => ReverseBytes(value, RevSize.Rev32); - public static ulong ReverseBytes64(ulong value) => ReverseBytes(value, RevSize.Rev64); - - private enum RevSize - { - Rev16, - Rev32, - Rev64 - } - - private static ulong ReverseBytes(ulong value, RevSize size) - { - value = ((value & 0xff00ff00ff00ff00) >> 8) | ((value & 0x00ff00ff00ff00ff) << 8); - - if (size == RevSize.Rev16) - { - return value; - } - - value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16); - - if (size == RevSize.Rev32) - { - return value; - } - - value = ((value & 0xffffffff00000000) >> 32) | ((value & 0x00000000ffffffff) << 32); - - if (size == RevSize.Rev64) - { - return value; - } - - throw new ArgumentException(nameof(size)); - } -#endregion - -#region "MultiplyHigh" - public static long SMulHi128(long left, long right) - { - long result = (long)UMulHi128((ulong)left, (ulong)right); - - if (left < 0) - { - result -= right; - } - - if (right < 0) - { - result -= left; - } - - return result; - } - - public static ulong UMulHi128(ulong left, ulong right) - { - ulong lHigh = left >> 32; - ulong lLow = left & 0xFFFFFFFF; - ulong rHigh = right >> 32; - ulong rLow = right & 0xFFFFFFFF; - - ulong z2 = lLow * rLow; - ulong t = lHigh * rLow + (z2 >> 32); - ulong z1 = t & 0xFFFFFFFF; - ulong z0 = t >> 32; - - z1 += lLow * rHigh; - - return lHigh * rHigh + z0 + (z1 >> 32); - } -#endregion - } -} diff --git a/ChocolArm64/Instructions/SoftFloat.cs b/ChocolArm64/Instructions/SoftFloat.cs deleted file mode 100644 index e78932cc..00000000 --- a/ChocolArm64/Instructions/SoftFloat.cs +++ /dev/null @@ -1,2790 +0,0 @@ -using ChocolArm64.State; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace ChocolArm64.Instructions -{ - static class SoftFloat - { - static SoftFloat() - { - RecipEstimateTable = BuildRecipEstimateTable(); - RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable(); - } - - internal static readonly byte[] RecipEstimateTable; - internal static readonly byte[] RecipSqrtEstimateTable; - - private static byte[] BuildRecipEstimateTable() - { - byte[] tbl = new byte[256]; - - for (int idx = 0; idx < 256; idx++) - { - uint src = (uint)idx + 256u; - - Debug.Assert(256u <= src && src < 512u); - - src = (src << 1) + 1u; - - uint aux = (1u << 19) / src; - - uint dst = (aux + 1u) >> 1; - - Debug.Assert(256u <= dst && dst < 512u); - - tbl[idx] = (byte)(dst - 256u); - } - - return tbl; - } - - private static byte[] BuildRecipSqrtEstimateTable() - { - byte[] tbl = new byte[384]; - - for (int idx = 0; idx < 384; idx++) - { - uint src = (uint)idx + 128u; - - Debug.Assert(128u <= src && src < 512u); - - if (src < 256u) - { - src = (src << 1) + 1u; - } - else - { - src = (src >> 1) << 1; - src = (src + 1u) << 1; - } - - uint aux = 512u; - - while (src * (aux + 1u) * (aux + 1u) < (1u << 28)) - { - aux = aux + 1u; - } - - uint dst = (aux + 1u) >> 1; - - Debug.Assert(256u <= dst && dst < 512u); - - tbl[idx] = (byte)(dst - 256u); - } - - return tbl; - } - } - - static class SoftFloat16_32 - { - public static float FPConvert(ushort valueBits, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat16_32.FPConvert: state.Fpcr = 0x{state.CFpcr:X8}"); - - double real = valueBits.FPUnpackCv(out FpType type, out bool sign, state); - - float result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - if (state.GetFpcrFlag(Fpcr.Dn)) - { - result = FPDefaultNaN(); - } - else - { - result = FPConvertNaN(valueBits); - } - - if (type == FpType.SNaN) - { - FPProcessException(FpExc.InvalidOp, state); - } - } - else if (type == FpType.Infinity) - { - result = FPInfinity(sign); - } - else if (type == FpType.Zero) - { - result = FPZero(sign); - } - else - { - result = FPRoundCv(real, state); - } - - return result; - } - - private static float FPDefaultNaN() - { - return -float.NaN; - } - - private static float FPInfinity(bool sign) - { - return sign ? float.NegativeInfinity : float.PositiveInfinity; - } - - private static float FPZero(bool sign) - { - return sign ? -0f : +0f; - } - - private static float FPMaxNormal(bool sign) - { - return sign ? float.MinValue : float.MaxValue; - } - - private static double FPUnpackCv( - this ushort valueBits, - out FpType type, - out bool sign, - CpuThreadState state) - { - sign = (~(uint)valueBits & 0x8000u) == 0u; - - uint exp16 = ((uint)valueBits & 0x7C00u) >> 10; - uint frac16 = (uint)valueBits & 0x03FFu; - - double real; - - if (exp16 == 0u) - { - if (frac16 == 0u) - { - type = FpType.Zero; - real = 0d; - } - else - { - type = FpType.Nonzero; // Subnormal. - real = Math.Pow(2d, -14) * ((double)frac16 * Math.Pow(2d, -10)); - } - } - else if (exp16 == 0x1Fu && !state.GetFpcrFlag(Fpcr.Ahp)) - { - if (frac16 == 0u) - { - type = FpType.Infinity; - real = Math.Pow(2d, 1000); - } - else - { - type = (~frac16 & 0x0200u) == 0u ? FpType.QNaN : FpType.SNaN; - real = 0d; - } - } - else - { - type = FpType.Nonzero; // Normal. - real = Math.Pow(2d, (int)exp16 - 15) * (1d + (double)frac16 * Math.Pow(2d, -10)); - } - - return sign ? -real : real; - } - - private static float FPRoundCv(double real, CpuThreadState state) - { - const int minimumExp = -126; - - const int e = 8; - const int f = 23; - - bool sign; - double mantissa; - - if (real < 0d) - { - sign = true; - mantissa = -real; - } - else - { - sign = false; - mantissa = real; - } - - int exponent = 0; - - while (mantissa < 1d) - { - mantissa *= 2d; - exponent--; - } - - while (mantissa >= 2d) - { - mantissa /= 2d; - exponent++; - } - - if (state.GetFpcrFlag(Fpcr.Fz) && exponent < minimumExp) - { - state.SetFpsrFlag(Fpsr.Ufc); - - return FPZero(sign); - } - - uint biasedExp = (uint)Math.Max(exponent - minimumExp + 1, 0); - - if (biasedExp == 0u) - { - mantissa /= Math.Pow(2d, minimumExp - exponent); - } - - uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, f)); - double error = mantissa * Math.Pow(2d, f) - (double)intMant; - - if (biasedExp == 0u && (error != 0d || state.GetFpcrFlag(Fpcr.Ufe))) - { - FPProcessException(FpExc.Underflow, state); - } - - bool overflowToInf; - bool roundUp; - - switch (state.FPRoundingMode()) - { - default: - case RoundMode.ToNearest: - roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u)); - overflowToInf = true; - break; - - case RoundMode.TowardsPlusInfinity: - roundUp = (error != 0d && !sign); - overflowToInf = !sign; - break; - - case RoundMode.TowardsMinusInfinity: - roundUp = (error != 0d && sign); - overflowToInf = sign; - break; - - case RoundMode.TowardsZero: - roundUp = false; - overflowToInf = false; - break; - } - - if (roundUp) - { - intMant++; - - if (intMant == 1u << f) - { - biasedExp = 1u; - } - - if (intMant == 1u << (f + 1)) - { - biasedExp++; - intMant >>= 1; - } - } - - float result; - - if (biasedExp >= (1u << e) - 1u) - { - result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign); - - FPProcessException(FpExc.Overflow, state); - - error = 1d; - } - else - { - result = BitConverter.Int32BitsToSingle( - (int)((sign ? 1u : 0u) << 31 | (biasedExp & 0xFFu) << 23 | (intMant & 0x007FFFFFu))); - } - - if (error != 0d) - { - FPProcessException(FpExc.Inexact, state); - } - - return result; - } - - private static float FPConvertNaN(ushort valueBits) - { - return BitConverter.Int32BitsToSingle( - (int)(((uint)valueBits & 0x8000u) << 16 | 0x7FC00000u | ((uint)valueBits & 0x01FFu) << 13)); - } - - private static void FPProcessException(FpExc exc, CpuThreadState state) - { - int enable = (int)exc + 8; - - if ((state.CFpcr & (1 << enable)) != 0) - { - throw new NotImplementedException("Floating-point trap handling."); - } - else - { - state.CFpsr |= 1 << (int)exc; - } - } - } - - static class SoftFloat32_16 - { - public static ushort FPConvert(float value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32_16.FPConvert: state.Fpcr = 0x{state.CFpcr:X8}"); - - double real = value.FPUnpackCv(out FpType type, out bool sign, out uint valueBits, state); - - bool altHp = state.GetFpcrFlag(Fpcr.Ahp); - - ushort resultBits; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - if (altHp) - { - resultBits = FPZero(sign); - } - else if (state.GetFpcrFlag(Fpcr.Dn)) - { - resultBits = FPDefaultNaN(); - } - else - { - resultBits = FPConvertNaN(valueBits); - } - - if (type == FpType.SNaN || altHp) - { - FPProcessException(FpExc.InvalidOp, state); - } - } - else if (type == FpType.Infinity) - { - if (altHp) - { - resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu); - - FPProcessException(FpExc.InvalidOp, state); - } - else - { - resultBits = FPInfinity(sign); - } - } - else if (type == FpType.Zero) - { - resultBits = FPZero(sign); - } - else - { - resultBits = FPRoundCv(real, state); - } - - return resultBits; - } - - private static ushort FPDefaultNaN() - { - return (ushort)0x7E00u; - } - - private static ushort FPInfinity(bool sign) - { - return sign ? (ushort)0xFC00u : (ushort)0x7C00u; - } - - private static ushort FPZero(bool sign) - { - return sign ? (ushort)0x8000u : (ushort)0x0000u; - } - - private static ushort FPMaxNormal(bool sign) - { - return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu; - } - - private static double FPUnpackCv( - this float value, - out FpType type, - out bool sign, - out uint valueBits, - CpuThreadState state) - { - valueBits = (uint)BitConverter.SingleToInt32Bits(value); - - sign = (~valueBits & 0x80000000u) == 0u; - - uint exp32 = (valueBits & 0x7F800000u) >> 23; - uint frac32 = valueBits & 0x007FFFFFu; - - double real; - - if (exp32 == 0u) - { - if (frac32 == 0u || state.GetFpcrFlag(Fpcr.Fz)) - { - type = FpType.Zero; - real = 0d; - - if (frac32 != 0u) - { - FPProcessException(FpExc.InputDenorm, state); - } - } - else - { - type = FpType.Nonzero; // Subnormal. - real = Math.Pow(2d, -126) * ((double)frac32 * Math.Pow(2d, -23)); - } - } - else if (exp32 == 0xFFu) - { - if (frac32 == 0u) - { - type = FpType.Infinity; - real = Math.Pow(2d, 1000); - } - else - { - type = (~frac32 & 0x00400000u) == 0u ? FpType.QNaN : FpType.SNaN; - real = 0d; - } - } - else - { - type = FpType.Nonzero; // Normal. - real = Math.Pow(2d, (int)exp32 - 127) * (1d + (double)frac32 * Math.Pow(2d, -23)); - } - - return sign ? -real : real; - } - - private static ushort FPRoundCv(double real, CpuThreadState state) - { - const int minimumExp = -14; - - const int e = 5; - const int f = 10; - - bool sign; - double mantissa; - - if (real < 0d) - { - sign = true; - mantissa = -real; - } - else - { - sign = false; - mantissa = real; - } - - int exponent = 0; - - while (mantissa < 1d) - { - mantissa *= 2d; - exponent--; - } - - while (mantissa >= 2d) - { - mantissa /= 2d; - exponent++; - } - - uint biasedExp = (uint)Math.Max(exponent - minimumExp + 1, 0); - - if (biasedExp == 0u) - { - mantissa /= Math.Pow(2d, minimumExp - exponent); - } - - uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, f)); - double error = mantissa * Math.Pow(2d, f) - (double)intMant; - - if (biasedExp == 0u && (error != 0d || state.GetFpcrFlag(Fpcr.Ufe))) - { - FPProcessException(FpExc.Underflow, state); - } - - bool overflowToInf; - bool roundUp; - - switch (state.FPRoundingMode()) - { - default: - case RoundMode.ToNearest: - roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u)); - overflowToInf = true; - break; - - case RoundMode.TowardsPlusInfinity: - roundUp = (error != 0d && !sign); - overflowToInf = !sign; - break; - - case RoundMode.TowardsMinusInfinity: - roundUp = (error != 0d && sign); - overflowToInf = sign; - break; - - case RoundMode.TowardsZero: - roundUp = false; - overflowToInf = false; - break; - } - - if (roundUp) - { - intMant++; - - if (intMant == 1u << f) - { - biasedExp = 1u; - } - - if (intMant == 1u << (f + 1)) - { - biasedExp++; - intMant >>= 1; - } - } - - ushort resultBits; - - if (!state.GetFpcrFlag(Fpcr.Ahp)) - { - if (biasedExp >= (1u << e) - 1u) - { - resultBits = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign); - - FPProcessException(FpExc.Overflow, state); - - error = 1d; - } - else - { - resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu)); - } - } - else - { - if (biasedExp >= 1u << e) - { - resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu); - - FPProcessException(FpExc.InvalidOp, state); - - error = 0d; - } - else - { - resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu)); - } - } - - if (error != 0d) - { - FPProcessException(FpExc.Inexact, state); - } - - return resultBits; - } - - private static ushort FPConvertNaN(uint valueBits) - { - return (ushort)((valueBits & 0x80000000u) >> 16 | 0x7E00u | (valueBits & 0x003FE000u) >> 13); - } - - private static void FPProcessException(FpExc exc, CpuThreadState state) - { - int enable = (int)exc + 8; - - if ((state.CFpcr & (1 << enable)) != 0) - { - throw new NotImplementedException("Floating-point trap handling."); - } - else - { - state.CFpsr |= 1 << (int)exc; - } - } - } - - static class SoftFloat32 - { - public static float FPAdd(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPAdd: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if (inf1 && inf2 && sign1 == !sign2) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if ((inf1 && !sign1) || (inf2 && !sign2)) - { - result = FPInfinity(false); - } - else if ((inf1 && sign1) || (inf2 && sign2)) - { - result = FPInfinity(true); - } - else if (zero1 && zero2 && sign1 == sign2) - { - result = FPZero(sign1); - } - else - { - result = value1 + value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - public static int FPCompare(float value1, float value2, bool signalNaNs, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPCompare: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out _, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out _, state); - - int result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = 0b0011; - - if (type1 == FpType.SNaN || type2 == FpType.SNaN || signalNaNs) - { - FPProcessException(FpExc.InvalidOp, state); - } - } - else - { - if (value1 == value2) - { - result = 0b0110; - } - else if (value1 < value2) - { - result = 0b1000; - } - else - { - result = 0b0010; - } - } - - return result; - } - - public static float FPCompareEQ(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPCompareEQ: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out _, out _, state); - value2 = value2.FPUnpack(out FpType type2, out _, out _, state); - - float result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = ZerosOrOnes(false); - - if (type1 == FpType.SNaN || type2 == FpType.SNaN) - { - FPProcessException(FpExc.InvalidOp, state); - } - } - else - { - result = ZerosOrOnes(value1 == value2); - } - - return result; - } - - public static float FPCompareGE(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPCompareGE: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out _, out _, state); - value2 = value2.FPUnpack(out FpType type2, out _, out _, state); - - float result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = ZerosOrOnes(false); - - FPProcessException(FpExc.InvalidOp, state); - } - else - { - result = ZerosOrOnes(value1 >= value2); - } - - return result; - } - - public static float FPCompareGT(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPCompareGT: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out _, out _, state); - value2 = value2.FPUnpack(out FpType type2, out _, out _, state); - - float result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = ZerosOrOnes(false); - - FPProcessException(FpExc.InvalidOp, state); - } - else - { - result = ZerosOrOnes(value1 > value2); - } - - return result; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float FPCompareLE(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPCompareLE: state.Fpcr = 0x{state.CFpcr:X8}"); - - return FPCompareGE(value2, value1, state); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float FPCompareLT(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPCompareLT: state.Fpcr = 0x{state.CFpcr:X8}"); - - return FPCompareGT(value2, value1, state); - } - - public static float FPDiv(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPDiv: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && inf2) || (zero1 && zero2)) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if (inf1 || zero2) - { - result = FPInfinity(sign1 ^ sign2); - - if (!inf1) - { - FPProcessException(FpExc.DivideByZero, state); - } - } - else if (zero1 || inf2) - { - result = FPZero(sign1 ^ sign2); - } - else - { - result = value1 / value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - public static float FPMax(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMax: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - if (value1 > value2) - { - if (type1 == FpType.Infinity) - { - result = FPInfinity(sign1); - } - else if (type1 == FpType.Zero) - { - result = FPZero(sign1 && sign2); - } - else - { - result = value1; - } - } - else - { - if (type2 == FpType.Infinity) - { - result = FPInfinity(sign2); - } - else if (type2 == FpType.Zero) - { - result = FPZero(sign1 && sign2); - } - else - { - result = value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - } - - return result; - } - - public static float FPMaxNum(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMaxNum: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1.FPUnpack(out FpType type1, out _, out _, state); - value2.FPUnpack(out FpType type2, out _, out _, state); - - if (type1 == FpType.QNaN && type2 != FpType.QNaN) - { - value1 = FPInfinity(true); - } - else if (type1 != FpType.QNaN && type2 == FpType.QNaN) - { - value2 = FPInfinity(true); - } - - return FPMax(value1, value2, state); - } - - public static float FPMin(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMin: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - if (value1 < value2) - { - if (type1 == FpType.Infinity) - { - result = FPInfinity(sign1); - } - else if (type1 == FpType.Zero) - { - result = FPZero(sign1 || sign2); - } - else - { - result = value1; - } - } - else - { - if (type2 == FpType.Infinity) - { - result = FPInfinity(sign2); - } - else if (type2 == FpType.Zero) - { - result = FPZero(sign1 || sign2); - } - else - { - result = value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - } - - return result; - } - - public static float FPMinNum(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMinNum: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1.FPUnpack(out FpType type1, out _, out _, state); - value2.FPUnpack(out FpType type2, out _, out _, state); - - if (type1 == FpType.QNaN && type2 != FpType.QNaN) - { - value1 = FPInfinity(false); - } - else if (type1 != FpType.QNaN && type2 == FpType.QNaN) - { - value2 = FPInfinity(false); - } - - return FPMin(value1, value2, state); - } - - public static float FPMul(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMul: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else if (zero1 || zero2) - { - result = FPZero(sign1 ^ sign2); - } - else - { - result = value1 * value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - public static float FPMulAdd( - float valueA, - float value1, - float value2, - CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMulAdd: state.Fpcr = 0x{state.CFpcr:X8}"); - - valueA = valueA.FPUnpack(out FpType typeA, out bool signA, out uint addend, state); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - float result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, state); - - if (typeA == FpType.QNaN && ((inf1 && zero2) || (zero1 && inf2))) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - - if (!done) - { - bool infA = typeA == FpType.Infinity; bool zeroA = typeA == FpType.Zero; - - bool signP = sign1 ^ sign2; - bool infP = inf1 || inf2; - bool zeroP = zero1 || zero2; - - if ((inf1 && zero2) || (zero1 && inf2) || (infA && infP && signA != signP)) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if ((infA && !signA) || (infP && !signP)) - { - result = FPInfinity(false); - } - else if ((infA && signA) || (infP && signP)) - { - result = FPInfinity(true); - } - else if (zeroA && zeroP && signA == signP) - { - result = FPZero(signA); - } - else - { - // TODO: When available, use: T MathF.FusedMultiplyAdd(T, T, T); - // https://github.com/dotnet/corefx/issues/31903 - - result = valueA + (value1 * value2); - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float FPMulSub( - float valueA, - float value1, - float value2, - CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMulSub: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPNeg(); - - return FPMulAdd(valueA, value1, value2, state); - } - - public static float FPMulX(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPMulX: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPTwo(sign1 ^ sign2); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else if (zero1 || zero2) - { - result = FPZero(sign1 ^ sign2); - } - else - { - result = value1 * value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - public static float FPRecipEstimate(float value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPRecipEstimate: state.Fpcr = 0x{state.CFpcr:X8}"); - - value.FPUnpack(out FpType type, out bool sign, out uint op, state); - - float result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else if (type == FpType.Infinity) - { - result = FPZero(sign); - } - else if (type == FpType.Zero) - { - result = FPInfinity(sign); - - FPProcessException(FpExc.DivideByZero, state); - } - else if (MathF.Abs(value) < MathF.Pow(2f, -128)) - { - bool overflowToInf; - - switch (state.FPRoundingMode()) - { - default: - case RoundMode.ToNearest: overflowToInf = true; break; - case RoundMode.TowardsPlusInfinity: overflowToInf = !sign; break; - case RoundMode.TowardsMinusInfinity: overflowToInf = sign; break; - case RoundMode.TowardsZero: overflowToInf = false; break; - } - - result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign); - - FPProcessException(FpExc.Overflow, state); - FPProcessException(FpExc.Inexact, state); - } - else if (state.GetFpcrFlag(Fpcr.Fz) && (MathF.Abs(value) >= MathF.Pow(2f, 126))) - { - result = FPZero(sign); - - state.SetFpsrFlag(Fpsr.Ufc); - } - else - { - ulong fraction = (ulong)(op & 0x007FFFFFu) << 29; - uint exp = (op & 0x7F800000u) >> 23; - - if (exp == 0u) - { - if ((fraction & 0x0008000000000000ul) == 0ul) - { - fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2; - exp -= 1u; - } - else - { - fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1; - } - } - - uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44); - - uint resultExp = 253u - exp; - - uint estimate = (uint)SoftFloat.RecipEstimateTable[scaled - 256u] + 256u; - - fraction = (ulong)(estimate & 0xFFu) << 44; - - if (resultExp == 0u) - { - fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1; - } - else if (resultExp + 1u == 0u) - { - fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2; - resultExp = 0u; - } - - result = BitConverter.Int32BitsToSingle( - (int)((sign ? 1u : 0u) << 31 | (resultExp & 0xFFu) << 23 | (uint)(fraction >> 29) & 0x007FFFFFu)); - } - - return result; - } - - public static float FPRecipStepFused(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPRecipStepFused: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPNeg(); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPTwo(false); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else - { - // TODO: When available, use: T MathF.FusedMultiplyAdd(T, T, T); - // https://github.com/dotnet/corefx/issues/31903 - - result = 2f + (value1 * value2); - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - public static float FPRecpX(float value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPRecpX: state.Fpcr = 0x{state.CFpcr:X8}"); - - value.FPUnpack(out FpType type, out bool sign, out uint op, state); - - float result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else - { - uint notExp = (~op >> 23) & 0xFFu; - uint maxExp = 0xFEu; - - result = BitConverter.Int32BitsToSingle( - (int)((sign ? 1u : 0u) << 31 | (notExp == 0xFFu ? maxExp : notExp) << 23)); - } - - return result; - } - - public static float FPRSqrtEstimate(float value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPRSqrtEstimate: state.Fpcr = 0x{state.CFpcr:X8}"); - - value.FPUnpack(out FpType type, out bool sign, out uint op, state); - - float result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else if (type == FpType.Zero) - { - result = FPInfinity(sign); - - FPProcessException(FpExc.DivideByZero, state); - } - else if (sign) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if (type == FpType.Infinity) - { - result = FPZero(false); - } - else - { - ulong fraction = (ulong)(op & 0x007FFFFFu) << 29; - uint exp = (op & 0x7F800000u) >> 23; - - if (exp == 0u) - { - while ((fraction & 0x0008000000000000ul) == 0ul) - { - fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1; - exp -= 1u; - } - - fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1; - } - - uint scaled; - - if ((exp & 1u) == 0u) - { - scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44); - } - else - { - scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45); - } - - uint resultExp = (380u - exp) >> 1; - - uint estimate = (uint)SoftFloat.RecipSqrtEstimateTable[scaled - 128u] + 256u; - - result = BitConverter.Int32BitsToSingle((int)((resultExp & 0xFFu) << 23 | (estimate & 0xFFu) << 15)); - } - - return result; - } - - public static float FPRSqrtStepFused(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPRSqrtStepFused: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPNeg(); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPOnePointFive(false); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else - { - // TODO: When available, use: T MathF.FusedMultiplyAdd(T, T, T); - // https://github.com/dotnet/corefx/issues/31903 - - result = (3f + (value1 * value2)) / 2f; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - public static float FPSqrt(float value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPSqrt: state.Fpcr = 0x{state.CFpcr:X8}"); - - value = value.FPUnpack(out FpType type, out bool sign, out uint op, state); - - float result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else if (type == FpType.Zero) - { - result = FPZero(sign); - } - else if (type == FpType.Infinity && !sign) - { - result = FPInfinity(sign); - } - else if (sign) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else - { - result = MathF.Sqrt(value); - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - - return result; - } - - public static float FPSub(float value1, float value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat32.FPSub: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out uint op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out uint op2, state); - - float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if (inf1 && inf2 && sign1 == sign2) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if ((inf1 && !sign1) || (inf2 && sign2)) - { - result = FPInfinity(false); - } - else if ((inf1 && sign1) || (inf2 && !sign2)) - { - result = FPInfinity(true); - } - else if (zero1 && zero2 && sign1 == !sign2) - { - result = FPZero(sign1); - } - else - { - result = value1 - value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && float.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0f); - } - } - } - - return result; - } - - private static float FPDefaultNaN() - { - return -float.NaN; - } - - private static float FPInfinity(bool sign) - { - return sign ? float.NegativeInfinity : float.PositiveInfinity; - } - - private static float FPZero(bool sign) - { - return sign ? -0f : +0f; - } - - private static float FPMaxNormal(bool sign) - { - return sign ? float.MinValue : float.MaxValue; - } - - private static float FPTwo(bool sign) - { - return sign ? -2f : +2f; - } - - private static float FPOnePointFive(bool sign) - { - return sign ? -1.5f : +1.5f; - } - - private static float FPNeg(this float value) - { - return -value; - } - - private static float ZerosOrOnes(bool ones) - { - return BitConverter.Int32BitsToSingle(ones ? -1 : 0); - } - - private static float FPUnpack( - this float value, - out FpType type, - out bool sign, - out uint valueBits, - CpuThreadState state) - { - valueBits = (uint)BitConverter.SingleToInt32Bits(value); - - sign = (~valueBits & 0x80000000u) == 0u; - - if ((valueBits & 0x7F800000u) == 0u) - { - if ((valueBits & 0x007FFFFFu) == 0u || state.GetFpcrFlag(Fpcr.Fz)) - { - type = FpType.Zero; - value = FPZero(sign); - - if ((valueBits & 0x007FFFFFu) != 0u) - { - FPProcessException(FpExc.InputDenorm, state); - } - } - else - { - type = FpType.Nonzero; - } - } - else if ((~valueBits & 0x7F800000u) == 0u) - { - if ((valueBits & 0x007FFFFFu) == 0u) - { - type = FpType.Infinity; - } - else - { - type = (~valueBits & 0x00400000u) == 0u ? FpType.QNaN : FpType.SNaN; - value = FPZero(sign); - } - } - else - { - type = FpType.Nonzero; - } - - return value; - } - - private static float FPProcessNaNs( - FpType type1, - FpType type2, - uint op1, - uint op2, - out bool done, - CpuThreadState state) - { - done = true; - - if (type1 == FpType.SNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.SNaN) - { - return FPProcessNaN(type2, op2, state); - } - else if (type1 == FpType.QNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.QNaN) - { - return FPProcessNaN(type2, op2, state); - } - - done = false; - - return FPZero(false); - } - - private static float FPProcessNaNs3( - FpType type1, - FpType type2, - FpType type3, - uint op1, - uint op2, - uint op3, - out bool done, - CpuThreadState state) - { - done = true; - - if (type1 == FpType.SNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.SNaN) - { - return FPProcessNaN(type2, op2, state); - } - else if (type3 == FpType.SNaN) - { - return FPProcessNaN(type3, op3, state); - } - else if (type1 == FpType.QNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.QNaN) - { - return FPProcessNaN(type2, op2, state); - } - else if (type3 == FpType.QNaN) - { - return FPProcessNaN(type3, op3, state); - } - - done = false; - - return FPZero(false); - } - - private static float FPProcessNaN(FpType type, uint op, CpuThreadState state) - { - if (type == FpType.SNaN) - { - op |= 1u << 22; - - FPProcessException(FpExc.InvalidOp, state); - } - - if (state.GetFpcrFlag(Fpcr.Dn)) - { - return FPDefaultNaN(); - } - - return BitConverter.Int32BitsToSingle((int)op); - } - - private static void FPProcessException(FpExc exc, CpuThreadState state) - { - int enable = (int)exc + 8; - - if ((state.CFpcr & (1 << enable)) != 0) - { - throw new NotImplementedException("Floating-point trap handling."); - } - else - { - state.CFpsr |= 1 << (int)exc; - } - } - } - - static class SoftFloat64 - { - public static double FPAdd(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPAdd: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if (inf1 && inf2 && sign1 == !sign2) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if ((inf1 && !sign1) || (inf2 && !sign2)) - { - result = FPInfinity(false); - } - else if ((inf1 && sign1) || (inf2 && sign2)) - { - result = FPInfinity(true); - } - else if (zero1 && zero2 && sign1 == sign2) - { - result = FPZero(sign1); - } - else - { - result = value1 + value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - public static int FPCompare(double value1, double value2, bool signalNaNs, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPCompare: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out _, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out _, state); - - int result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = 0b0011; - - if (type1 == FpType.SNaN || type2 == FpType.SNaN || signalNaNs) - { - FPProcessException(FpExc.InvalidOp, state); - } - } - else - { - if (value1 == value2) - { - result = 0b0110; - } - else if (value1 < value2) - { - result = 0b1000; - } - else - { - result = 0b0010; - } - } - - return result; - } - - public static double FPCompareEQ(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPCompareEQ: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out _, out _, state); - value2 = value2.FPUnpack(out FpType type2, out _, out _, state); - - double result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = ZerosOrOnes(false); - - if (type1 == FpType.SNaN || type2 == FpType.SNaN) - { - FPProcessException(FpExc.InvalidOp, state); - } - } - else - { - result = ZerosOrOnes(value1 == value2); - } - - return result; - } - - public static double FPCompareGE(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPCompareGE: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out _, out _, state); - value2 = value2.FPUnpack(out FpType type2, out _, out _, state); - - double result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = ZerosOrOnes(false); - - FPProcessException(FpExc.InvalidOp, state); - } - else - { - result = ZerosOrOnes(value1 >= value2); - } - - return result; - } - - public static double FPCompareGT(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPCompareGT: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out _, out _, state); - value2 = value2.FPUnpack(out FpType type2, out _, out _, state); - - double result; - - if (type1 == FpType.SNaN || type1 == FpType.QNaN || type2 == FpType.SNaN || type2 == FpType.QNaN) - { - result = ZerosOrOnes(false); - - FPProcessException(FpExc.InvalidOp, state); - } - else - { - result = ZerosOrOnes(value1 > value2); - } - - return result; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double FPCompareLE(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPCompareLE: state.Fpcr = 0x{state.CFpcr:X8}"); - - return FPCompareGE(value2, value1, state); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double FPCompareLT(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPCompareLT: state.Fpcr = 0x{state.CFpcr:X8}"); - - return FPCompareGT(value2, value1, state); - } - - public static double FPDiv(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPDiv: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && inf2) || (zero1 && zero2)) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if (inf1 || zero2) - { - result = FPInfinity(sign1 ^ sign2); - - if (!inf1) - { - FPProcessException(FpExc.DivideByZero, state); - } - } - else if (zero1 || inf2) - { - result = FPZero(sign1 ^ sign2); - } - else - { - result = value1 / value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - public static double FPMax(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMax: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - if (value1 > value2) - { - if (type1 == FpType.Infinity) - { - result = FPInfinity(sign1); - } - else if (type1 == FpType.Zero) - { - result = FPZero(sign1 && sign2); - } - else - { - result = value1; - } - } - else - { - if (type2 == FpType.Infinity) - { - result = FPInfinity(sign2); - } - else if (type2 == FpType.Zero) - { - result = FPZero(sign1 && sign2); - } - else - { - result = value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - } - - return result; - } - - public static double FPMaxNum(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMaxNum: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1.FPUnpack(out FpType type1, out _, out _, state); - value2.FPUnpack(out FpType type2, out _, out _, state); - - if (type1 == FpType.QNaN && type2 != FpType.QNaN) - { - value1 = FPInfinity(true); - } - else if (type1 != FpType.QNaN && type2 == FpType.QNaN) - { - value2 = FPInfinity(true); - } - - return FPMax(value1, value2, state); - } - - public static double FPMin(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMin: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - if (value1 < value2) - { - if (type1 == FpType.Infinity) - { - result = FPInfinity(sign1); - } - else if (type1 == FpType.Zero) - { - result = FPZero(sign1 || sign2); - } - else - { - result = value1; - } - } - else - { - if (type2 == FpType.Infinity) - { - result = FPInfinity(sign2); - } - else if (type2 == FpType.Zero) - { - result = FPZero(sign1 || sign2); - } - else - { - result = value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - } - - return result; - } - - public static double FPMinNum(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMinNum: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1.FPUnpack(out FpType type1, out _, out _, state); - value2.FPUnpack(out FpType type2, out _, out _, state); - - if (type1 == FpType.QNaN && type2 != FpType.QNaN) - { - value1 = FPInfinity(false); - } - else if (type1 != FpType.QNaN && type2 == FpType.QNaN) - { - value2 = FPInfinity(false); - } - - return FPMin(value1, value2, state); - } - - public static double FPMul(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMul: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else if (zero1 || zero2) - { - result = FPZero(sign1 ^ sign2); - } - else - { - result = value1 * value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - public static double FPMulAdd( - double valueA, - double value1, - double value2, - CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMulAdd: state.Fpcr = 0x{state.CFpcr:X8}"); - - valueA = valueA.FPUnpack(out FpType typeA, out bool signA, out ulong addend, state); - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - double result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, state); - - if (typeA == FpType.QNaN && ((inf1 && zero2) || (zero1 && inf2))) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - - if (!done) - { - bool infA = typeA == FpType.Infinity; bool zeroA = typeA == FpType.Zero; - - bool signP = sign1 ^ sign2; - bool infP = inf1 || inf2; - bool zeroP = zero1 || zero2; - - if ((inf1 && zero2) || (zero1 && inf2) || (infA && infP && signA != signP)) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if ((infA && !signA) || (infP && !signP)) - { - result = FPInfinity(false); - } - else if ((infA && signA) || (infP && signP)) - { - result = FPInfinity(true); - } - else if (zeroA && zeroP && signA == signP) - { - result = FPZero(signA); - } - else - { - // TODO: When available, use: T Math.FusedMultiplyAdd(T, T, T); - // https://github.com/dotnet/corefx/issues/31903 - - result = valueA + (value1 * value2); - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double FPMulSub( - double valueA, - double value1, - double value2, - CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMulSub: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPNeg(); - - return FPMulAdd(valueA, value1, value2, state); - } - - public static double FPMulX(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPMulX: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPTwo(sign1 ^ sign2); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else if (zero1 || zero2) - { - result = FPZero(sign1 ^ sign2); - } - else - { - result = value1 * value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - public static double FPRecipEstimate(double value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPRecipEstimate: state.Fpcr = 0x{state.CFpcr:X8}"); - - value.FPUnpack(out FpType type, out bool sign, out ulong op, state); - - double result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else if (type == FpType.Infinity) - { - result = FPZero(sign); - } - else if (type == FpType.Zero) - { - result = FPInfinity(sign); - - FPProcessException(FpExc.DivideByZero, state); - } - else if (Math.Abs(value) < Math.Pow(2d, -1024)) - { - bool overflowToInf; - - switch (state.FPRoundingMode()) - { - default: - case RoundMode.ToNearest: overflowToInf = true; break; - case RoundMode.TowardsPlusInfinity: overflowToInf = !sign; break; - case RoundMode.TowardsMinusInfinity: overflowToInf = sign; break; - case RoundMode.TowardsZero: overflowToInf = false; break; - } - - result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign); - - FPProcessException(FpExc.Overflow, state); - FPProcessException(FpExc.Inexact, state); - } - else if (state.GetFpcrFlag(Fpcr.Fz) && (Math.Abs(value) >= Math.Pow(2d, 1022))) - { - result = FPZero(sign); - - state.SetFpsrFlag(Fpsr.Ufc); - } - else - { - ulong fraction = op & 0x000FFFFFFFFFFFFFul; - uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52); - - if (exp == 0u) - { - if ((fraction & 0x0008000000000000ul) == 0ul) - { - fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2; - exp -= 1u; - } - else - { - fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1; - } - } - - uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44); - - uint resultExp = 2045u - exp; - - uint estimate = (uint)SoftFloat.RecipEstimateTable[scaled - 256u] + 256u; - - fraction = (ulong)(estimate & 0xFFu) << 44; - - if (resultExp == 0u) - { - fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1; - } - else if (resultExp + 1u == 0u) - { - fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2; - resultExp = 0u; - } - - result = BitConverter.Int64BitsToDouble( - (long)((sign ? 1ul : 0ul) << 63 | (resultExp & 0x7FFul) << 52 | (fraction & 0x000FFFFFFFFFFFFFul))); - } - - return result; - } - - public static double FPRecipStepFused(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPRecipStepFused: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPNeg(); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPTwo(false); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else - { - // TODO: When available, use: T Math.FusedMultiplyAdd(T, T, T); - // https://github.com/dotnet/corefx/issues/31903 - - result = 2d + (value1 * value2); - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - public static double FPRecpX(double value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPRecpX: state.Fpcr = 0x{state.CFpcr:X8}"); - - value.FPUnpack(out FpType type, out bool sign, out ulong op, state); - - double result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else - { - ulong notExp = (~op >> 52) & 0x7FFul; - ulong maxExp = 0x7FEul; - - result = BitConverter.Int64BitsToDouble( - (long)((sign ? 1ul : 0ul) << 63 | (notExp == 0x7FFul ? maxExp : notExp) << 52)); - } - - return result; - } - - public static double FPRSqrtEstimate(double value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPRSqrtEstimate: state.Fpcr = 0x{state.CFpcr:X8}"); - - value.FPUnpack(out FpType type, out bool sign, out ulong op, state); - - double result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else if (type == FpType.Zero) - { - result = FPInfinity(sign); - - FPProcessException(FpExc.DivideByZero, state); - } - else if (sign) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if (type == FpType.Infinity) - { - result = FPZero(false); - } - else - { - ulong fraction = op & 0x000FFFFFFFFFFFFFul; - uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52); - - if (exp == 0u) - { - while ((fraction & 0x0008000000000000ul) == 0ul) - { - fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1; - exp -= 1u; - } - - fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1; - } - - uint scaled; - - if ((exp & 1u) == 0u) - { - scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44); - } - else - { - scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45); - } - - uint resultExp = (3068u - exp) >> 1; - - uint estimate = (uint)SoftFloat.RecipSqrtEstimateTable[scaled - 128u] + 256u; - - result = BitConverter.Int64BitsToDouble((long)((resultExp & 0x7FFul) << 52 | (estimate & 0xFFul) << 44)); - } - - return result; - } - - public static double FPRSqrtStepFused(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPRSqrtStepFused: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPNeg(); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if ((inf1 && zero2) || (zero1 && inf2)) - { - result = FPOnePointFive(false); - } - else if (inf1 || inf2) - { - result = FPInfinity(sign1 ^ sign2); - } - else - { - // TODO: When available, use: T Math.FusedMultiplyAdd(T, T, T); - // https://github.com/dotnet/corefx/issues/31903 - - result = (3d + (value1 * value2)) / 2d; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - public static double FPSqrt(double value, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPSqrt: state.Fpcr = 0x{state.CFpcr:X8}"); - - value = value.FPUnpack(out FpType type, out bool sign, out ulong op, state); - - double result; - - if (type == FpType.SNaN || type == FpType.QNaN) - { - result = FPProcessNaN(type, op, state); - } - else if (type == FpType.Zero) - { - result = FPZero(sign); - } - else if (type == FpType.Infinity && !sign) - { - result = FPInfinity(sign); - } - else if (sign) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else - { - result = Math.Sqrt(value); - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - - return result; - } - - public static double FPSub(double value1, double value2, CpuThreadState state) - { - Debug.WriteLineIf(state.CFpcr != 0, $"SoftFloat64.FPSub: state.Fpcr = 0x{state.CFpcr:X8}"); - - value1 = value1.FPUnpack(out FpType type1, out bool sign1, out ulong op1, state); - value2 = value2.FPUnpack(out FpType type2, out bool sign2, out ulong op2, state); - - double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, state); - - if (!done) - { - bool inf1 = type1 == FpType.Infinity; bool zero1 = type1 == FpType.Zero; - bool inf2 = type2 == FpType.Infinity; bool zero2 = type2 == FpType.Zero; - - if (inf1 && inf2 && sign1 == sign2) - { - result = FPDefaultNaN(); - - FPProcessException(FpExc.InvalidOp, state); - } - else if ((inf1 && !sign1) || (inf2 && sign2)) - { - result = FPInfinity(false); - } - else if ((inf1 && sign1) || (inf2 && !sign2)) - { - result = FPInfinity(true); - } - else if (zero1 && zero2 && sign1 == !sign2) - { - result = FPZero(sign1); - } - else - { - result = value1 - value2; - - if (state.GetFpcrFlag(Fpcr.Fz) && double.IsSubnormal(result)) - { - state.SetFpsrFlag(Fpsr.Ufc); - - result = FPZero(result < 0d); - } - } - } - - return result; - } - - private static double FPDefaultNaN() - { - return -double.NaN; - } - - private static double FPInfinity(bool sign) - { - return sign ? double.NegativeInfinity : double.PositiveInfinity; - } - - private static double FPZero(bool sign) - { - return sign ? -0d : +0d; - } - - private static double FPMaxNormal(bool sign) - { - return sign ? double.MinValue : double.MaxValue; - } - - private static double FPTwo(bool sign) - { - return sign ? -2d : +2d; - } - - private static double FPOnePointFive(bool sign) - { - return sign ? -1.5d : +1.5d; - } - - private static double FPNeg(this double value) - { - return -value; - } - - private static double ZerosOrOnes(bool ones) - { - return BitConverter.Int64BitsToDouble(ones ? -1L : 0L); - } - - private static double FPUnpack( - this double value, - out FpType type, - out bool sign, - out ulong valueBits, - CpuThreadState state) - { - valueBits = (ulong)BitConverter.DoubleToInt64Bits(value); - - sign = (~valueBits & 0x8000000000000000ul) == 0ul; - - if ((valueBits & 0x7FF0000000000000ul) == 0ul) - { - if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul || state.GetFpcrFlag(Fpcr.Fz)) - { - type = FpType.Zero; - value = FPZero(sign); - - if ((valueBits & 0x000FFFFFFFFFFFFFul) != 0ul) - { - FPProcessException(FpExc.InputDenorm, state); - } - } - else - { - type = FpType.Nonzero; - } - } - else if ((~valueBits & 0x7FF0000000000000ul) == 0ul) - { - if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul) - { - type = FpType.Infinity; - } - else - { - type = (~valueBits & 0x0008000000000000ul) == 0ul ? FpType.QNaN : FpType.SNaN; - value = FPZero(sign); - } - } - else - { - type = FpType.Nonzero; - } - - return value; - } - - private static double FPProcessNaNs( - FpType type1, - FpType type2, - ulong op1, - ulong op2, - out bool done, - CpuThreadState state) - { - done = true; - - if (type1 == FpType.SNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.SNaN) - { - return FPProcessNaN(type2, op2, state); - } - else if (type1 == FpType.QNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.QNaN) - { - return FPProcessNaN(type2, op2, state); - } - - done = false; - - return FPZero(false); - } - - private static double FPProcessNaNs3( - FpType type1, - FpType type2, - FpType type3, - ulong op1, - ulong op2, - ulong op3, - out bool done, - CpuThreadState state) - { - done = true; - - if (type1 == FpType.SNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.SNaN) - { - return FPProcessNaN(type2, op2, state); - } - else if (type3 == FpType.SNaN) - { - return FPProcessNaN(type3, op3, state); - } - else if (type1 == FpType.QNaN) - { - return FPProcessNaN(type1, op1, state); - } - else if (type2 == FpType.QNaN) - { - return FPProcessNaN(type2, op2, state); - } - else if (type3 == FpType.QNaN) - { - return FPProcessNaN(type3, op3, state); - } - - done = false; - - return FPZero(false); - } - - private static double FPProcessNaN(FpType type, ulong op, CpuThreadState state) - { - if (type == FpType.SNaN) - { - op |= 1ul << 51; - - FPProcessException(FpExc.InvalidOp, state); - } - - if (state.GetFpcrFlag(Fpcr.Dn)) - { - return FPDefaultNaN(); - } - - return BitConverter.Int64BitsToDouble((long)op); - } - - private static void FPProcessException(FpExc exc, CpuThreadState state) - { - int enable = (int)exc + 8; - - if ((state.CFpcr & (1 << enable)) != 0) - { - throw new NotImplementedException("Floating-point trap handling."); - } - else - { - state.CFpsr |= 1 << (int)exc; - } - } - } -} diff --git a/ChocolArm64/Instructions/VectorHelper.cs b/ChocolArm64/Instructions/VectorHelper.cs deleted file mode 100644 index 4d57e285..00000000 --- a/ChocolArm64/Instructions/VectorHelper.cs +++ /dev/null @@ -1,646 +0,0 @@ -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Runtime.CompilerServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace ChocolArm64.Instructions -{ - static class VectorHelper - { - public static void EmitCall(ILEmitterCtx context, string name64, string name128) - { - bool isSimd64 = context.CurrOp.RegisterSize == RegisterSize.Simd64; - - context.EmitCall(typeof(VectorHelper), isSimd64 ? name64 : name128); - } - - public static void EmitCall(ILEmitterCtx context, string mthdName) - { - context.EmitCall(typeof(VectorHelper), mthdName); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SatF32ToS32(float value) - { - if (float.IsNaN(value)) return 0; - - return value >= int.MaxValue ? int.MaxValue : - value <= int.MinValue ? int.MinValue : (int)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SatF32ToS64(float value) - { - if (float.IsNaN(value)) return 0; - - return value >= long.MaxValue ? long.MaxValue : - value <= long.MinValue ? long.MinValue : (long)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint SatF32ToU32(float value) - { - if (float.IsNaN(value)) return 0; - - return value >= uint.MaxValue ? uint.MaxValue : - value <= uint.MinValue ? uint.MinValue : (uint)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SatF32ToU64(float value) - { - if (float.IsNaN(value)) return 0; - - return value >= ulong.MaxValue ? ulong.MaxValue : - value <= ulong.MinValue ? ulong.MinValue : (ulong)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SatF64ToS32(double value) - { - if (double.IsNaN(value)) return 0; - - return value >= int.MaxValue ? int.MaxValue : - value <= int.MinValue ? int.MinValue : (int)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SatF64ToS64(double value) - { - if (double.IsNaN(value)) return 0; - - return value >= long.MaxValue ? long.MaxValue : - value <= long.MinValue ? long.MinValue : (long)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint SatF64ToU32(double value) - { - if (double.IsNaN(value)) return 0; - - return value >= uint.MaxValue ? uint.MaxValue : - value <= uint.MinValue ? uint.MinValue : (uint)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SatF64ToU64(double value) - { - if (double.IsNaN(value)) return 0; - - return value >= ulong.MaxValue ? ulong.MaxValue : - value <= ulong.MinValue ? ulong.MinValue : (ulong)value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double Round(double value, CpuThreadState state) - { - RoundMode roundMode = state.FPRoundingMode(); - - if (roundMode == RoundMode.ToNearest) - { - return Math.Round(value); // even - } - else if (roundMode == RoundMode.TowardsPlusInfinity) - { - return Math.Ceiling(value); - } - else if (roundMode == RoundMode.TowardsMinusInfinity) - { - return Math.Floor(value); - } - else /* if (roundMode == RoundMode.TowardsZero) */ - { - return Math.Truncate(value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float RoundF(float value, CpuThreadState state) - { - RoundMode roundMode = state.FPRoundingMode(); - - if (roundMode == RoundMode.ToNearest) - { - return MathF.Round(value); // even - } - else if (roundMode == RoundMode.TowardsPlusInfinity) - { - return MathF.Ceiling(value); - } - else if (roundMode == RoundMode.TowardsMinusInfinity) - { - return MathF.Floor(value); - } - else /* if (roundMode == RoundMode.TowardsZero) */ - { - return MathF.Truncate(value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<double> Sse41ScalarRound(Vector128<double> upper, Vector128<double> value, CpuThreadState state) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - RoundMode roundMode = state.FPRoundingMode(); - - if (roundMode == RoundMode.ToNearest) - { - return Sse41.RoundToNearestIntegerScalar(upper, value); // even - } - else if (roundMode == RoundMode.TowardsPlusInfinity) - { - return Sse41.RoundToPositiveInfinityScalar(upper, value); - } - else if (roundMode == RoundMode.TowardsMinusInfinity) - { - return Sse41.RoundToNegativeInfinityScalar(upper, value); - } - else /* if (roundMode == RoundMode.TowardsZero) */ - { - return Sse41.RoundToZeroScalar(upper, value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> Sse41ScalarRoundF(Vector128<float> upper, Vector128<float> value, CpuThreadState state) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - RoundMode roundMode = state.FPRoundingMode(); - - if (roundMode == RoundMode.ToNearest) - { - return Sse41.RoundToNearestIntegerScalar(upper, value); // even - } - else if (roundMode == RoundMode.TowardsPlusInfinity) - { - return Sse41.RoundToPositiveInfinityScalar(upper, value); - } - else if (roundMode == RoundMode.TowardsMinusInfinity) - { - return Sse41.RoundToNegativeInfinityScalar(upper, value); - } - else /* if (roundMode == RoundMode.TowardsZero) */ - { - return Sse41.RoundToZeroScalar(upper, value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<double> Sse41VectorRound(Vector128<double> value, CpuThreadState state) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - RoundMode roundMode = state.FPRoundingMode(); - - if (roundMode == RoundMode.ToNearest) - { - return Sse41.RoundToNearestInteger(value); // even - } - else if (roundMode == RoundMode.TowardsPlusInfinity) - { - return Sse41.RoundToPositiveInfinity(value); - } - else if (roundMode == RoundMode.TowardsMinusInfinity) - { - return Sse41.RoundToNegativeInfinity(value); - } - else /* if (roundMode == RoundMode.TowardsZero) */ - { - return Sse41.RoundToZero(value); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> Sse41VectorRoundF(Vector128<float> value, CpuThreadState state) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - RoundMode roundMode = state.FPRoundingMode(); - - if (roundMode == RoundMode.ToNearest) - { - return Sse41.RoundToNearestInteger(value); // even - } - else if (roundMode == RoundMode.TowardsPlusInfinity) - { - return Sse41.RoundToPositiveInfinity(value); - } - else if (roundMode == RoundMode.TowardsMinusInfinity) - { - return Sse41.RoundToNegativeInfinity(value); - } - else /* if (roundMode == RoundMode.TowardsZero) */ - { - return Sse41.RoundToZero(value); - } - } - - public static Vector128<float> Tbl1_V64( - Vector128<float> vector, - Vector128<float> tb0) - { - return Tbl(vector, 8, tb0); - } - - public static Vector128<float> Tbl1_V128( - Vector128<float> vector, - Vector128<float> tb0) - { - return Tbl(vector, 16, tb0); - } - - public static Vector128<float> Tbl2_V64( - Vector128<float> vector, - Vector128<float> tb0, - Vector128<float> tb1) - { - return Tbl(vector, 8, tb0, tb1); - } - - public static Vector128<float> Tbl2_V128( - Vector128<float> vector, - Vector128<float> tb0, - Vector128<float> tb1) - { - return Tbl(vector, 16, tb0, tb1); - } - - public static Vector128<float> Tbl3_V64( - Vector128<float> vector, - Vector128<float> tb0, - Vector128<float> tb1, - Vector128<float> tb2) - { - return Tbl(vector, 8, tb0, tb1, tb2); - } - - public static Vector128<float> Tbl3_V128( - Vector128<float> vector, - Vector128<float> tb0, - Vector128<float> tb1, - Vector128<float> tb2) - { - return Tbl(vector, 16, tb0, tb1, tb2); - } - - public static Vector128<float> Tbl4_V64( - Vector128<float> vector, - Vector128<float> tb0, - Vector128<float> tb1, - Vector128<float> tb2, - Vector128<float> tb3) - { - return Tbl(vector, 8, tb0, tb1, tb2, tb3); - } - - public static Vector128<float> Tbl4_V128( - Vector128<float> vector, - Vector128<float> tb0, - Vector128<float> tb1, - Vector128<float> tb2, - Vector128<float> tb3) - { - return Tbl(vector, 16, tb0, tb1, tb2, tb3); - } - - private static Vector128<float> Tbl(Vector128<float> vector, int bytes, params Vector128<float>[] tb) - { - Vector128<float> res = new Vector128<float>(); - - byte[] table = new byte[tb.Length * 16]; - - for (byte index = 0; index < tb.Length; index++) - for (byte index2 = 0; index2 < 16; index2++) - { - table[index * 16 + index2] = (byte)VectorExtractIntZx(tb[index], index2, 0); - } - - for (byte index = 0; index < bytes; index++) - { - byte tblIdx = (byte)VectorExtractIntZx(vector, index, 0); - - if (tblIdx < table.Length) - { - res = VectorInsertInt(table[tblIdx], res, index, 0); - } - } - - return res; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double VectorExtractDouble(Vector128<float> vector, byte index) - { - if (Sse41.IsSupported) - { - return BitConverter.Int64BitsToDouble(Sse41.Extract(Sse.StaticCast<float, long>(vector), index)); - } - else if (Sse2.IsSupported) - { - return BitConverter.Int64BitsToDouble((long)VectorExtractIntZx(vector, index, 3)); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long VectorExtractIntSx(Vector128<float> vector, byte index, int size) - { - if (Sse41.IsSupported) - { - if (size == 0) - { - return (sbyte)Sse41.Extract(Sse.StaticCast<float, byte>(vector), index); - } - else if (size == 1) - { - return (short)Sse2.Extract(Sse.StaticCast<float, ushort>(vector), index); - } - else if (size == 2) - { - return Sse41.Extract(Sse.StaticCast<float, int>(vector), index); - } - else if (size == 3) - { - return Sse41.Extract(Sse.StaticCast<float, long>(vector), index); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - else if (Sse2.IsSupported) - { - if (size == 0) - { - return (sbyte)VectorExtractIntZx(vector, index, size); - } - else if (size == 1) - { - return (short)VectorExtractIntZx(vector, index, size); - } - else if (size == 2) - { - return (int)VectorExtractIntZx(vector, index, size); - } - else if (size == 3) - { - return (long)VectorExtractIntZx(vector, index, size); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong VectorExtractIntZx(Vector128<float> vector, byte index, int size) - { - if (Sse41.IsSupported) - { - if (size == 0) - { - return Sse41.Extract(Sse.StaticCast<float, byte>(vector), index); - } - else if (size == 1) - { - return Sse2.Extract(Sse.StaticCast<float, ushort>(vector), index); - } - else if (size == 2) - { - return Sse41.Extract(Sse.StaticCast<float, uint>(vector), index); - } - else if (size == 3) - { - return Sse41.Extract(Sse.StaticCast<float, ulong>(vector), index); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - else if (Sse2.IsSupported) - { - int shortIdx = size == 0 - ? index >> 1 - : index << (size - 1); - - ushort value = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)shortIdx); - - if (size == 0) - { - return (byte)(value >> (index & 1) * 8); - } - else if (size == 1) - { - return value; - } - else if (size == 2 || size == 3) - { - ushort value1 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 1)); - - if (size == 2) - { - return (uint)(value | (value1 << 16)); - } - - ushort value2 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 2)); - ushort value3 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 3)); - - return ((ulong)value << 0) | - ((ulong)value1 << 16) | - ((ulong)value2 << 32) | - ((ulong)value3 << 48); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float VectorExtractSingle(Vector128<float> vector, byte index) - { - if (Sse41.IsSupported) - { - return Sse41.Extract(vector, index); - } - else if (Sse2.IsSupported) - { - Vector128<ushort> shortVector = Sse.StaticCast<float, ushort>(vector); - - int low = Sse2.Extract(shortVector, (byte)(index * 2 + 0)); - int high = Sse2.Extract(shortVector, (byte)(index * 2 + 1)); - - return BitConverter.Int32BitsToSingle(low | (high << 16)); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> VectorInsertDouble(double value, Vector128<float> vector, byte index) - { - return VectorInsertInt((ulong)BitConverter.DoubleToInt64Bits(value), vector, index, 3); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> VectorInsertInt(ulong value, Vector128<float> vector, byte index, int size) - { - if (Sse41.IsSupported) - { - if (size == 0) - { - return Sse.StaticCast<byte, float>(Sse41.Insert(Sse.StaticCast<float, byte>(vector), (byte)value, index)); - } - else if (size == 1) - { - return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(vector), (ushort)value, index)); - } - else if (size == 2) - { - return Sse.StaticCast<uint, float>(Sse41.Insert(Sse.StaticCast<float, uint>(vector), (uint)value, index)); - } - else if (size == 3) - { - return Sse.StaticCast<ulong, float>(Sse41.Insert(Sse.StaticCast<float, ulong>(vector), value, index)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - else if (Sse2.IsSupported) - { - Vector128<ushort> shortVector = Sse.StaticCast<float, ushort>(vector); - - int shortIdx = size == 0 - ? index >> 1 - : index << (size - 1); - - if (size == 0) - { - ushort shortVal = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)shortIdx); - - int shift = (index & 1) * 8; - - shortVal &= (ushort)(0xff00 >> shift); - - shortVal |= (ushort)((byte)value << shift); - - return Sse.StaticCast<ushort, float>(Sse2.Insert(shortVector, shortVal, (byte)shortIdx)); - } - else if (size == 1) - { - return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(vector), (ushort)value, index)); - } - else if (size == 2 || size == 3) - { - shortVector = Sse2.Insert(shortVector, (ushort)(value >> 0), (byte)(shortIdx + 0)); - shortVector = Sse2.Insert(shortVector, (ushort)(value >> 16), (byte)(shortIdx + 1)); - - if (size == 3) - { - shortVector = Sse2.Insert(shortVector, (ushort)(value >> 32), (byte)(shortIdx + 2)); - shortVector = Sse2.Insert(shortVector, (ushort)(value >> 48), (byte)(shortIdx + 3)); - } - - return Sse.StaticCast<ushort, float>(shortVector); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> VectorInsertSingle(float value, Vector128<float> vector, byte index) - { - if (Sse41.IsSupported) - { - // Note: The if/else if is necessary to enable the JIT to - // produce a single INSERTPS instruction instead of the - // jump table fallback. - if (index == 0) - { - return Sse41.Insert(vector, value, 0x00); - } - else if (index == 1) - { - return Sse41.Insert(vector, value, 0x10); - } - else if (index == 2) - { - return Sse41.Insert(vector, value, 0x20); - } - else if (index == 3) - { - return Sse41.Insert(vector, value, 0x30); - } - else - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - else if (Sse2.IsSupported) - { - int intValue = BitConverter.SingleToInt32Bits(value); - - ushort low = (ushort)(intValue >> 0); - ushort high = (ushort)(intValue >> 16); - - Vector128<ushort> shortVector = Sse.StaticCast<float, ushort>(vector); - - shortVector = Sse2.Insert(shortVector, low, (byte)(index * 2 + 0)); - shortVector = Sse2.Insert(shortVector, high, (byte)(index * 2 + 1)); - - return Sse.StaticCast<ushort, float>(shortVector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> Sse41VectorInsertScalarSingle(float value, Vector128<float> vector) - { - // Note: 0b1110 is the mask to zero the upper bits. - return Sse41.Insert(vector, value, 0b1110); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128<float> VectorSingleZero() - { - if (Sse.IsSupported) - { - return Sse.SetZeroVector128(); - } - - throw new PlatformNotSupportedException(); - } - } -} |
