Skip to content

Commit 8a2aec1

Browse files
Intrinsics analyzer and fixes (#85481)
* Implement analyzer for platform intrinsics use in System.Private.CoreLib This analyzer detects the use of all platform intrinsics and checks to ensure that they are all used either protected by an if statement OR ternary operator which checks an appropriate IsSupported flag, or that the intrinsic is used within a method where the behavior of platform support for the intrinsic is not allowed to vary between compile time and runtime. The analyzer attempts to be conservative about allowed patterns. All existing code in System.Private.CoreLib has been annotated to avoid producing errors. See the markdown document for details. Co-authored-by: Jeremy Koritzinsky <[email protected]>
1 parent 4242567 commit 8a2aec1

39 files changed

+2399
-227
lines changed

docs/design/coreclr/botr/vectors-and-intrinsics.md

Lines changed: 88 additions & 113 deletions
Large diffs are not rendered by default.

src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,4 +1334,369 @@ public void Set64BitInstructionSetVariantsUnconditionally(TargetArchitecture arc
13341334
}
13351335
}
13361336
}
1337+
public static class InstructionSetParser
1338+
{
1339+
public static InstructionSet LookupPlatformIntrinsicInstructionSet(TargetArchitecture targetArch, TypeDesc intrinsicType)
1340+
{
1341+
MetadataType metadataType = intrinsicType.GetTypeDefinition() as MetadataType;
1342+
if (metadataType == null)
1343+
return InstructionSet.ILLEGAL;
1344+
1345+
string namespaceName;
1346+
string typeName = metadataType.Name;
1347+
string nestedTypeName = null;
1348+
if (metadataType.ContainingType != null)
1349+
{
1350+
var enclosingType = (MetadataType)metadataType.ContainingType;
1351+
namespaceName = enclosingType.Namespace;
1352+
nestedTypeName = metadataType.Name;
1353+
typeName = enclosingType.Name;
1354+
}
1355+
else
1356+
{
1357+
namespaceName = metadataType.Namespace;
1358+
}
1359+
1360+
string platformIntrinsicNamespace;
1361+
1362+
switch (targetArch)
1363+
{
1364+
case TargetArchitecture.ARM64:
1365+
platformIntrinsicNamespace = "System.Runtime.Intrinsics.Arm";
1366+
break;
1367+
1368+
case TargetArchitecture.X64:
1369+
case TargetArchitecture.X86:
1370+
platformIntrinsicNamespace = "System.Runtime.Intrinsics.X86";
1371+
break;
1372+
1373+
default:
1374+
return InstructionSet.ILLEGAL;
1375+
}
1376+
1377+
if (namespaceName != platformIntrinsicNamespace)
1378+
return InstructionSet.ILLEGAL;
1379+
1380+
switch (targetArch)
1381+
{
1382+
1383+
case TargetArchitecture.ARM64:
1384+
switch (typeName)
1385+
{
1386+
1387+
case "ArmBase":
1388+
if (nestedTypeName == "Arm64")
1389+
{ return InstructionSet.ARM64_ArmBase_Arm64; }
1390+
else
1391+
{ return InstructionSet.ARM64_ArmBase; }
1392+
1393+
case "AdvSimd":
1394+
if (nestedTypeName == "Arm64")
1395+
{ return InstructionSet.ARM64_AdvSimd_Arm64; }
1396+
else
1397+
{ return InstructionSet.ARM64_AdvSimd; }
1398+
1399+
case "Aes":
1400+
if (nestedTypeName == "Arm64")
1401+
{ return InstructionSet.ARM64_Aes_Arm64; }
1402+
else
1403+
{ return InstructionSet.ARM64_Aes; }
1404+
1405+
case "Crc32":
1406+
if (nestedTypeName == "Arm64")
1407+
{ return InstructionSet.ARM64_Crc32_Arm64; }
1408+
else
1409+
{ return InstructionSet.ARM64_Crc32; }
1410+
1411+
case "Dp":
1412+
if (nestedTypeName == "Arm64")
1413+
{ return InstructionSet.ARM64_Dp_Arm64; }
1414+
else
1415+
{ return InstructionSet.ARM64_Dp; }
1416+
1417+
case "Rdm":
1418+
if (nestedTypeName == "Arm64")
1419+
{ return InstructionSet.ARM64_Rdm_Arm64; }
1420+
else
1421+
{ return InstructionSet.ARM64_Rdm; }
1422+
1423+
case "Sha1":
1424+
if (nestedTypeName == "Arm64")
1425+
{ return InstructionSet.ARM64_Sha1_Arm64; }
1426+
else
1427+
{ return InstructionSet.ARM64_Sha1; }
1428+
1429+
case "Sha256":
1430+
if (nestedTypeName == "Arm64")
1431+
{ return InstructionSet.ARM64_Sha256_Arm64; }
1432+
else
1433+
{ return InstructionSet.ARM64_Sha256; }
1434+
1435+
}
1436+
break;
1437+
1438+
case TargetArchitecture.X64:
1439+
switch (typeName)
1440+
{
1441+
1442+
case "X86Base":
1443+
if (nestedTypeName == "X64")
1444+
{ return InstructionSet.X64_X86Base_X64; }
1445+
else
1446+
{ return InstructionSet.X64_X86Base; }
1447+
1448+
case "Sse":
1449+
if (nestedTypeName == "X64")
1450+
{ return InstructionSet.X64_SSE_X64; }
1451+
else
1452+
{ return InstructionSet.X64_SSE; }
1453+
1454+
case "Sse2":
1455+
if (nestedTypeName == "X64")
1456+
{ return InstructionSet.X64_SSE2_X64; }
1457+
else
1458+
{ return InstructionSet.X64_SSE2; }
1459+
1460+
case "Sse3":
1461+
if (nestedTypeName == "X64")
1462+
{ return InstructionSet.X64_SSE3_X64; }
1463+
else
1464+
{ return InstructionSet.X64_SSE3; }
1465+
1466+
case "Ssse3":
1467+
if (nestedTypeName == "X64")
1468+
{ return InstructionSet.X64_SSSE3_X64; }
1469+
else
1470+
{ return InstructionSet.X64_SSSE3; }
1471+
1472+
case "Sse41":
1473+
if (nestedTypeName == "X64")
1474+
{ return InstructionSet.X64_SSE41_X64; }
1475+
else
1476+
{ return InstructionSet.X64_SSE41; }
1477+
1478+
case "Sse42":
1479+
if (nestedTypeName == "X64")
1480+
{ return InstructionSet.X64_SSE42_X64; }
1481+
else
1482+
{ return InstructionSet.X64_SSE42; }
1483+
1484+
case "Avx":
1485+
if (nestedTypeName == "X64")
1486+
{ return InstructionSet.X64_AVX_X64; }
1487+
else
1488+
{ return InstructionSet.X64_AVX; }
1489+
1490+
case "Avx2":
1491+
if (nestedTypeName == "X64")
1492+
{ return InstructionSet.X64_AVX2_X64; }
1493+
else
1494+
{ return InstructionSet.X64_AVX2; }
1495+
1496+
case "Aes":
1497+
if (nestedTypeName == "X64")
1498+
{ return InstructionSet.X64_AES_X64; }
1499+
else
1500+
{ return InstructionSet.X64_AES; }
1501+
1502+
case "Bmi1":
1503+
if (nestedTypeName == "X64")
1504+
{ return InstructionSet.X64_BMI1_X64; }
1505+
else
1506+
{ return InstructionSet.X64_BMI1; }
1507+
1508+
case "Bmi2":
1509+
if (nestedTypeName == "X64")
1510+
{ return InstructionSet.X64_BMI2_X64; }
1511+
else
1512+
{ return InstructionSet.X64_BMI2; }
1513+
1514+
case "Fma":
1515+
if (nestedTypeName == "X64")
1516+
{ return InstructionSet.X64_FMA_X64; }
1517+
else
1518+
{ return InstructionSet.X64_FMA; }
1519+
1520+
case "Lzcnt":
1521+
if (nestedTypeName == "X64")
1522+
{ return InstructionSet.X64_LZCNT_X64; }
1523+
else
1524+
{ return InstructionSet.X64_LZCNT; }
1525+
1526+
case "Pclmulqdq":
1527+
if (nestedTypeName == "X64")
1528+
{ return InstructionSet.X64_PCLMULQDQ_X64; }
1529+
else
1530+
{ return InstructionSet.X64_PCLMULQDQ; }
1531+
1532+
case "Popcnt":
1533+
if (nestedTypeName == "X64")
1534+
{ return InstructionSet.X64_POPCNT_X64; }
1535+
else
1536+
{ return InstructionSet.X64_POPCNT; }
1537+
1538+
case "AvxVnni":
1539+
if (nestedTypeName == "X64")
1540+
{ return InstructionSet.X64_AVXVNNI_X64; }
1541+
else
1542+
{ return InstructionSet.X64_AVXVNNI; }
1543+
1544+
case "Movbe":
1545+
if (nestedTypeName == "X64")
1546+
{ return InstructionSet.X64_MOVBE_X64; }
1547+
else
1548+
{ return InstructionSet.X64_MOVBE; }
1549+
1550+
case "X86Serialize":
1551+
if (nestedTypeName == "X64")
1552+
{ return InstructionSet.X64_X86Serialize_X64; }
1553+
else
1554+
{ return InstructionSet.X64_X86Serialize; }
1555+
1556+
case "Avx512F":
1557+
if (nestedTypeName == "X64")
1558+
{ return InstructionSet.X64_AVX512F_X64; }
1559+
else
1560+
if (nestedTypeName == "VL")
1561+
{ return InstructionSet.X64_AVX512F_VL; }
1562+
else
1563+
{ return InstructionSet.X64_AVX512F; }
1564+
1565+
case "Avx512BW":
1566+
if (nestedTypeName == "X64")
1567+
{ return InstructionSet.X64_AVX512BW_X64; }
1568+
else
1569+
if (nestedTypeName == "VL")
1570+
{ return InstructionSet.X64_AVX512BW_VL; }
1571+
else
1572+
{ return InstructionSet.X64_AVX512BW; }
1573+
1574+
case "Avx512CD":
1575+
if (nestedTypeName == "X64")
1576+
{ return InstructionSet.X64_AVX512CD_X64; }
1577+
else
1578+
if (nestedTypeName == "VL")
1579+
{ return InstructionSet.X64_AVX512CD_VL; }
1580+
else
1581+
{ return InstructionSet.X64_AVX512CD; }
1582+
1583+
case "Avx512DQ":
1584+
if (nestedTypeName == "X64")
1585+
{ return InstructionSet.X64_AVX512DQ_X64; }
1586+
else
1587+
if (nestedTypeName == "VL")
1588+
{ return InstructionSet.X64_AVX512DQ_VL; }
1589+
else
1590+
{ return InstructionSet.X64_AVX512DQ; }
1591+
1592+
case "Avx512Vbmi":
1593+
if (nestedTypeName == "X64")
1594+
{ return InstructionSet.X64_AVX512VBMI_X64; }
1595+
else
1596+
if (nestedTypeName == "VL")
1597+
{ return InstructionSet.X64_AVX512VBMI_VL; }
1598+
else
1599+
{ return InstructionSet.X64_AVX512VBMI; }
1600+
1601+
}
1602+
break;
1603+
1604+
case TargetArchitecture.X86:
1605+
switch (typeName)
1606+
{
1607+
1608+
case "X86Base":
1609+
{ return InstructionSet.X86_X86Base; }
1610+
1611+
case "Sse":
1612+
{ return InstructionSet.X86_SSE; }
1613+
1614+
case "Sse2":
1615+
{ return InstructionSet.X86_SSE2; }
1616+
1617+
case "Sse3":
1618+
{ return InstructionSet.X86_SSE3; }
1619+
1620+
case "Ssse3":
1621+
{ return InstructionSet.X86_SSSE3; }
1622+
1623+
case "Sse41":
1624+
{ return InstructionSet.X86_SSE41; }
1625+
1626+
case "Sse42":
1627+
{ return InstructionSet.X86_SSE42; }
1628+
1629+
case "Avx":
1630+
{ return InstructionSet.X86_AVX; }
1631+
1632+
case "Avx2":
1633+
{ return InstructionSet.X86_AVX2; }
1634+
1635+
case "Aes":
1636+
{ return InstructionSet.X86_AES; }
1637+
1638+
case "Bmi1":
1639+
{ return InstructionSet.X86_BMI1; }
1640+
1641+
case "Bmi2":
1642+
{ return InstructionSet.X86_BMI2; }
1643+
1644+
case "Fma":
1645+
{ return InstructionSet.X86_FMA; }
1646+
1647+
case "Lzcnt":
1648+
{ return InstructionSet.X86_LZCNT; }
1649+
1650+
case "Pclmulqdq":
1651+
{ return InstructionSet.X86_PCLMULQDQ; }
1652+
1653+
case "Popcnt":
1654+
{ return InstructionSet.X86_POPCNT; }
1655+
1656+
case "AvxVnni":
1657+
{ return InstructionSet.X86_AVXVNNI; }
1658+
1659+
case "Movbe":
1660+
{ return InstructionSet.X86_MOVBE; }
1661+
1662+
case "X86Serialize":
1663+
{ return InstructionSet.X86_X86Serialize; }
1664+
1665+
case "Avx512F":
1666+
if (nestedTypeName == "VL")
1667+
{ return InstructionSet.X86_AVX512F_VL; }
1668+
else
1669+
{ return InstructionSet.X86_AVX512F; }
1670+
1671+
case "Avx512BW":
1672+
if (nestedTypeName == "VL")
1673+
{ return InstructionSet.X86_AVX512BW_VL; }
1674+
else
1675+
{ return InstructionSet.X86_AVX512BW; }
1676+
1677+
case "Avx512CD":
1678+
if (nestedTypeName == "VL")
1679+
{ return InstructionSet.X86_AVX512CD_VL; }
1680+
else
1681+
{ return InstructionSet.X86_AVX512CD; }
1682+
1683+
case "Avx512DQ":
1684+
if (nestedTypeName == "VL")
1685+
{ return InstructionSet.X86_AVX512DQ_VL; }
1686+
else
1687+
{ return InstructionSet.X86_AVX512DQ; }
1688+
1689+
case "Avx512Vbmi":
1690+
if (nestedTypeName == "VL")
1691+
{ return InstructionSet.X86_AVX512VBMI_VL; }
1692+
else
1693+
{ return InstructionSet.X86_AVX512VBMI; }
1694+
1695+
}
1696+
break;
1697+
1698+
}
1699+
return InstructionSet.ILLEGAL;
1700+
}
1701+
}
13371702
}

src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
; DO NOT CHANGE R2R NUMERIC VALUES OF THE EXISTING SETS. Changing R2R numeric values definitions would be R2R format breaking change.
2424

2525
; Definition of X86 instruction sets
26-
definearch ,X86 ,32Bit ,X64
26+
definearch ,X86 ,32Bit ,X64, X64
2727

2828
instructionset ,X86 ,X86Base , ,22 ,X86Base ,base
2929
instructionset ,X86 ,Sse , ,1 ,SSE ,sse
@@ -126,12 +126,12 @@ implication ,X86 ,AVX512VBMI ,AVX512BW
126126
implication ,X86 ,AVX512VBMI_VL ,AVX512BW_VL
127127

128128
; Definition of X64 instruction sets
129-
definearch ,X64 ,64Bit ,X64
129+
definearch ,X64 ,64Bit ,X64, X64
130130

131131
copyinstructionsets,X86 ,X64
132132

133133
; Definition of Arm64 instruction sets
134-
definearch ,ARM64 ,64Bit ,Arm64
134+
definearch ,ARM64 ,64Bit ,Arm64, Arm64
135135

136136
instructionset ,ARM64 ,ArmBase , ,16 ,ArmBase ,base
137137
instructionset ,ARM64 ,AdvSimd , ,17 ,AdvSimd ,neon

0 commit comments

Comments
 (0)