use std::collections::HashMap;
use crate::instruction::*;
use crate::llvm_intrinsics::*;
use crate::types::*;
use crate::x86::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types)]
pub enum X86Intrinsic {
Sse_AddPS,
Sse_AddSS,
Sse_SubPS,
Sse_SubSS,
Sse_MulPS,
Sse_MulSS,
Sse_DivPS,
Sse_DivSS,
Sse_MinPS,
Sse_MinSS,
Sse_MaxPS,
Sse_MaxSS,
Sse_SqrtPS,
Sse_SqrtSS,
Sse_RcpPS,
Sse_RcpSS,
Sse_RsqrtPS,
Sse_RsqrtSS,
Sse_CmpPS,
Sse_CmpSS,
Sse_ComiSS,
Sse_UComiSS,
Sse_CvtSS2SI,
Sse_CvtSS2SI64,
Sse_CvttSS2SI,
Sse_CvttSS2SI64,
Sse_CvtSI2SS,
Sse_CvtSI642SS,
Sse_MovHLPS,
Sse_MovLHPS,
Sse_MovMSKPS,
Sse_MovSS,
Sse_ShufPS,
Sse_UnpcklPS,
Sse_UnpckhPS,
Sse_AndPS,
Sse_AndnPS,
Sse_OrPS,
Sse_XorPS,
Sse_Prefetch,
Sse_Sfence,
Sse_MovntPS,
Sse_Movnti,
Sse_Maskmovq,
Sse_PavgB,
Sse_PavgW,
Sse_PextrW,
Sse_PinsrW,
Sse_PmaxSW,
Sse_PmaxUB,
Sse_PminSW,
Sse_PminUB,
Sse_PmovMSKB,
Sse_PmulhuW,
Sse_PsadBW,
Sse_PshufW,
Sse2_AddPD,
Sse2_AddSD,
Sse2_SubPD,
Sse2_SubSD,
Sse2_MulPD,
Sse2_MulSD,
Sse2_DivPD,
Sse2_DivSD,
Sse2_SqrtPD,
Sse2_SqrtSD,
Sse2_MinPD,
Sse2_MinSD,
Sse2_MaxPD,
Sse2_MaxSD,
Sse2_AndPD,
Sse2_AndnPD,
Sse2_OrPD,
Sse2_XorPD,
Sse2_CmpPD,
Sse2_CmpSD,
Sse2_ComiSD,
Sse2_UComiSD,
Sse2_CvtPD2PS,
Sse2_CvtPS2PD,
Sse2_CvtPD2DQ,
Sse2_CvtTPD2DQ,
Sse2_CvtDQ2PD,
Sse2_CvtDQ2PS,
Sse2_CvtPS2DQ,
Sse2_CvtTPS2DQ,
Sse2_CvtSD2SS,
Sse2_CvtSS2SD,
Sse2_CvtSD2SI,
Sse2_CvtSD2SI64,
Sse2_CvttSD2SI,
Sse2_CvttSD2SI64,
Sse2_CvtSI2SD,
Sse2_CvtSI642SD,
Sse2_MovAPD,
Sse2_MovUPD,
Sse2_MovMSKPD,
Sse2_MovSD,
Sse2_MovD,
Sse2_MovQ,
Sse2_MovDQA,
Sse2_MovDQU,
Sse2_MovntPD,
Sse2_MovntDQ,
Sse2_Movnti,
Sse2_ShufPD,
Sse2_UnpcklPD,
Sse2_UnpckhPD,
Sse2_PShufD,
Sse2_PShufHW,
Sse2_PShufLW,
Sse2_PAddB,
Sse2_PAddW,
Sse2_PAddD,
Sse2_PAddQ,
Sse2_PAddsB,
Sse2_PAddsW,
Sse2_PAddusB,
Sse2_PAddusW,
Sse2_PSubB,
Sse2_PSubW,
Sse2_PSubD,
Sse2_PSubQ,
Sse2_PSubsB,
Sse2_PSubsW,
Sse2_PSubusB,
Sse2_PSubusW,
Sse2_PMulLW,
Sse2_PMulHW,
Sse2_PMulhuW,
Sse2_PMaddW,
Sse2_PAvgB,
Sse2_PAvgW,
Sse2_PMinUB,
Sse2_PMinSW,
Sse2_PMaxUB,
Sse2_PMaxSW,
Sse2_PSadBW,
Sse2_PMovMSKB,
Sse2_PCmpEqB,
Sse2_PCmpEqW,
Sse2_PCmpEqD,
Sse2_PCmpGtB,
Sse2_PCmpGtW,
Sse2_PCmpGtD,
Sse2_PackSSWB,
Sse2_PackSSDW,
Sse2_PackUSWB,
Sse2_PUnpcklBW,
Sse2_PUnpcklWD,
Sse2_PUnpcklDQ,
Sse2_PUnpcklQDQ,
Sse2_PUnpckhBW,
Sse2_PUnpckhWD,
Sse2_PUnpckhDQ,
Sse2_PUnpckhQDQ,
Sse2_PSllW,
Sse2_PSllD,
Sse2_PSllQ,
Sse2_PSrlW,
Sse2_PSrlD,
Sse2_PSrlQ,
Sse2_PSraW,
Sse2_PSraD,
Sse2_PAnd,
Sse2_PAndn,
Sse2_POr,
Sse2_PXor,
Sse2_Clflush,
Sse2_LFence,
Sse2_MFence,
Sse2_Pause,
Sse2_MaskmovDQU,
Sse3_HAddPS,
Sse3_HAddPD,
Sse3_HSubPS,
Sse3_HSubPD,
Sse3_AddSubPS,
Sse3_AddSubPD,
Sse3_MovDDup,
Sse3_MovSHDup,
Sse3_MovSLDup,
Sse3_Lddqu,
Sse3_FistTP,
Sse3_Monitor,
Sse3_MWait,
Ssse3_PHAddW,
Ssse3_PHAddD,
Ssse3_PHAddSW,
Ssse3_PHSubW,
Ssse3_PHSubD,
Ssse3_PHSubSW,
Ssse3_PMaddUBSW,
Ssse3_PMulhrSW,
Ssse3_PShufB,
Ssse3_PSignB,
Ssse3_PSignW,
Ssse3_PSignD,
Ssse3_PAbsB,
Ssse3_PAbsW,
Ssse3_PAbsD,
Ssse3_PAlignr,
Sse41_PMulLD,
Sse41_PMulDQ,
Sse41_PMinSB,
Sse41_PMinSD,
Sse41_PMinUW,
Sse41_PMinUD,
Sse41_PMaxSB,
Sse41_PMaxSD,
Sse41_PMaxUW,
Sse41_PMaxUD,
Sse41_BlendPS,
Sse41_BlendPD,
Sse41_BlendvPS,
Sse41_BlendvPD,
Sse41_DppS,
Sse41_DppD,
Sse41_RoundPS,
Sse41_RoundPD,
Sse41_RoundSS,
Sse41_RoundSD,
Sse41_ExtractPS,
Sse41_InsertPS,
Sse41_MPsadbw,
Sse41_PackUSDW,
Sse41_PCmpEQQ,
Sse41_PTest,
Sse41_MovntDQA,
Sse41_PInsrB,
Sse41_PInsrW,
Sse41_PInsrD,
Sse41_PInsrQ,
Sse41_PExtrB,
Sse41_PExtrW,
Sse41_PExtrD,
Sse41_PExtrQ,
Sse41_PMovSXBD,
Sse41_PMovSXBW,
Sse41_PMovSXBQ,
Sse41_PMovSXDQ,
Sse41_PMovSXWD,
Sse41_PMovSXWQ,
Sse41_PMovZXBD,
Sse41_PMovZXBW,
Sse41_PMovZXBQ,
Sse41_PMovZXDQ,
Sse41_PMovZXWD,
Sse41_PMovZXWQ,
Sse42_PCmpIstrI,
Sse42_PCmpIstrM,
Sse42_Crc32_8,
Sse42_Crc32_16,
Sse42_Crc32_32,
Sse42_Crc32_64,
Sse42_Popcnt,
Aes_AesEnc,
Aes_AesEncLast,
Aes_AesDec,
Aes_AesDecLast,
Aes_AesIMC,
Aes_AesKeyGenAssist,
Aes_PCLmulQDQ,
Sha_Sha1Rnds4,
Sha_Sha1Nexte,
Sha_Sha1Msg1,
Sha_Sha1Msg2,
Sha_Sha256Rnds2,
Sha_Sha256Msg1,
Sha_Sha256Msg2,
RdRand16,
RdRand32,
RdRand64,
RdSeed16,
RdSeed32,
RdSeed64,
Avx_AddPS256,
Avx_AddPD256,
Avx_AddSS,
Avx_AddSD,
Avx_SubPS256,
Avx_SubPD256,
Avx_SubSS,
Avx_SubSD,
Avx_MulPS256,
Avx_MulPD256,
Avx_MulSS,
Avx_MulSD,
Avx_DivPS256,
Avx_DivPD256,
Avx_DivSS,
Avx_DivSD,
Avx_SqrtPS256,
Avx_SqrtPD256,
Avx_SqrtSS,
Avx_SqrtSD,
Avx_RcpPS256,
Avx_RsqrtPS256,
Avx_MinPS256,
Avx_MinPD256,
Avx_MinSS,
Avx_MinSD,
Avx_MaxPS256,
Avx_MaxPD256,
Avx_MaxSS,
Avx_MaxSD,
Avx_AndPS256,
Avx_AndPD256,
Avx_AndnPS256,
Avx_AndnPD256,
Avx_OrPS256,
Avx_OrPD256,
Avx_XorPS256,
Avx_XorPD256,
Avx_CmpPS256,
Avx_CmpPD256,
Avx_CmpSS,
Avx_CmpSD,
Avx_ComiSS,
Avx_UComiSS,
Avx_ComiSD,
Avx_UComiSD,
Avx_CvtPD2PS256,
Avx_CvtPS2PD256,
Avx_CvtDQ2PS256,
Avx_CvtPS2DQ256,
Avx_CvtTPS2DQ256,
Avx_CvtDQ2PD256,
Avx_CvtPD2DQ256,
Avx_CvtTPD2DQ256,
Avx_MovAPD256,
Avx_MovUPD256,
Avx_MovAPS256,
Avx_MovUPS256,
Avx_MovDQA256,
Avx_MovDQU256,
Avx_MovMSKPS256,
Avx_MovMSKPD256,
Avx_ShufPS256,
Avx_ShufPD256,
Avx_UnpcklPS256,
Avx_UnpckhPS256,
Avx_UnpcklPD256,
Avx_UnpckhPD256,
Avx_BroadcastSS,
Avx_BroadcastSD,
Avx_PermilvarPS,
Avx_PermilvarPD,
Avx_PermilPS,
Avx_PermilPD,
Avx_PermilvarPS256,
Avx_PermilvarPD256,
Avx_PermilPS256,
Avx_PermilPD256,
Avx_Perm2F128,
Avx_ZeroAll,
Avx_ZeroUpper,
Avx_MaskmovPS256,
Avx_MaskmovPD256,
Avx_HAddPS256,
Avx_HAddPD256,
Avx_HSubPS256,
Avx_HSubPD256,
Avx_AddSubPS256,
Avx_AddSubPD256,
Avx_MovDDup256,
Avx_MovSHDup256,
Avx_MovSLDup256,
Avx_Lddqu256,
Avx_BlendvPS256,
Avx_BlendvPD256,
Avx_BlendPS256,
Avx_BlendPD256,
Avx_DppS256,
Avx_DppD256,
Avx_RoundPS256,
Avx_RoundPD256,
Avx_PTest256,
Avx_MovntPS256,
Avx_MovntPD256,
Avx_MovntDQ256,
Avx2_PAddB256,
Avx2_PAddW256,
Avx2_PAddD256,
Avx2_PAddQ256,
Avx2_PSubB256,
Avx2_PSubW256,
Avx2_PSubD256,
Avx2_PSubQ256,
Avx2_PMulLW256,
Avx2_PMulHW256,
Avx2_PMaddW256,
Avx2_PMulLD256,
Avx2_PMulDQ256,
Avx2_PAnd256,
Avx2_PAndn256,
Avx2_POr256,
Avx2_PXor256,
Avx2_PSllvD256,
Avx2_PSllvQ256,
Avx2_PSrlvD256,
Avx2_PSrlvQ256,
Avx2_PSravD256,
Avx2_GatherDPS,
Avx2_GatherQPS,
Avx2_GatherDPD,
Avx2_GatherQPD,
Avx2_GatherDD,
Avx2_GatherQD,
Avx2_GatherDQ,
Avx2_GatherQQ,
Avx2_PBroadcastB128,
Avx2_PBroadcastW128,
Avx2_PBroadcastD128,
Avx2_PBroadcastQ128,
Avx2_PBroadcastB256,
Avx2_PBroadcastW256,
Avx2_PBroadcastD256,
Avx2_PBroadcastQ256,
Avx2_PermD256,
Avx2_PermPD256,
Avx2_Perm2I128,
Avx2_PackUSDW256,
Avx2_PHAddW256,
Avx2_PHAddD256,
Avx2_PHAddSW256,
Avx2_PHSubW256,
Avx2_PHSubD256,
Avx2_PHSubSW256,
Avx2_PMaddUBSW256,
Avx2_PMulhrSW256,
Avx2_PShufB256,
Avx2_PShufD256,
Fma_Fmadd132PS,
Fma_Fmadd132PD,
Fma_Fmadd132SS,
Fma_Fmadd132SD,
Fma_Fmadd213PS,
Fma_Fmadd213PD,
Fma_Fmadd213SS,
Fma_Fmadd213SD,
Fma_Fmadd231PS,
Fma_Fmadd231PD,
Fma_Fmadd231SS,
Fma_Fmadd231SD,
Fma_Fmsub132PS,
Fma_Fmsub132PD,
Fma_Fmsub132SS,
Fma_Fmsub132SD,
Fma_Fmsub213PS,
Fma_Fmsub213PD,
Fma_Fmsub213SS,
Fma_Fmsub213SD,
Fma_Fmsub231PS,
Fma_Fmsub231PD,
Fma_Fmsub231SS,
Fma_Fmsub231SD,
Fma_Fnmadd132PS,
Fma_Fnmadd132PD,
Fma_Fnmadd132SS,
Fma_Fnmadd132SD,
Fma_Fnmadd213PS,
Fma_Fnmadd213PD,
Fma_Fnmadd213SS,
Fma_Fnmadd213SD,
Fma_Fnmadd231PS,
Fma_Fnmadd231PD,
Fma_Fnmadd231SS,
Fma_Fnmadd231SD,
Fma_Fnmsub132PS,
Fma_Fnmsub132PD,
Fma_Fnmsub132SS,
Fma_Fnmsub132SD,
Fma_Fnmsub213PS,
Fma_Fnmsub213PD,
Fma_Fnmsub213SS,
Fma_Fnmsub213SD,
Fma_Fnmsub231PS,
Fma_Fnmsub231PD,
Fma_Fnmsub231SS,
Fma_Fnmsub231SD,
Fma_Fmaddsub132PS,
Fma_Fmaddsub132PD,
Fma_Fmaddsub213PS,
Fma_Fmaddsub213PD,
Fma_Fmaddsub231PS,
Fma_Fmaddsub231PD,
Fma_Fmsubadd132PS,
Fma_Fmsubadd132PD,
Fma_Fmsubadd213PS,
Fma_Fmsubadd213PD,
Fma_Fmsubadd231PS,
Fma_Fmsubadd231PD,
Fma_Fmadd132PS256,
Fma_Fmadd132PD256,
Fma_Fmadd213PS256,
Fma_Fmadd213PD256,
Fma_Fmadd231PS256,
Fma_Fmadd231PD256,
Fma_Fmsub132PS256,
Fma_Fmsub132PD256,
Fma_Fmsub213PS256,
Fma_Fmsub213PD256,
Fma_Fmsub231PS256,
Fma_Fmsub231PD256,
Fma_Fnmadd132PS256,
Fma_Fnmadd132PD256,
Fma_Fnmadd213PS256,
Fma_Fnmadd213PD256,
Fma_Fnmadd231PS256,
Fma_Fnmadd231PD256,
Fma_Fnmsub132PS256,
Fma_Fnmsub132PD256,
Fma_Fnmsub213PS256,
Fma_Fnmsub213PD256,
Fma_Fnmsub231PS256,
Fma_Fnmsub231PD256,
Fma_Fmaddsub132PS256,
Fma_Fmaddsub132PD256,
Fma_Fmaddsub213PS256,
Fma_Fmaddsub213PD256,
Fma_Fmaddsub231PS256,
Fma_Fmaddsub231PD256,
Fma_Fmsubadd132PS256,
Fma_Fmsubadd132PD256,
Fma_Fmsubadd213PS256,
Fma_Fmsubadd213PD256,
Fma_Fmsubadd231PS256,
Fma_Fmsubadd231PD256,
Bmi_Andn32,
Bmi_Andn64,
Bmi_Bextr32,
Bmi_Bextr64,
Bmi_Blsi32,
Bmi_Blsi64,
Bmi_Blsmsk32,
Bmi_Blsmsk64,
Bmi_Blsr32,
Bmi_Blsr64,
Bmi_Tzcnt16,
Bmi_Tzcnt32,
Bmi_Tzcnt64,
Bmi2_Bzhi32,
Bmi2_Bzhi64,
Bmi2_Mulx32,
Bmi2_Mulx64,
Bmi2_Pdep32,
Bmi2_Pdep64,
Bmi2_Pext32,
Bmi2_Pext64,
Bmi2_Rorx32,
Bmi2_Rorx64,
Bmi2_Sarx32,
Bmi2_Sarx64,
Bmi2_Shlx32,
Bmi2_Shlx64,
Bmi2_Shrx32,
Bmi2_Shrx64,
Adx_Adcx32,
Adx_Adcx64,
Adx_Adox32,
Adx_Adox64,
Misc_Clflushopt,
Misc_Clwb,
Misc_PrefetchW,
Misc_PrefetchWt1,
Misc_RdFSBase,
Misc_RdGSBase,
Misc_WrFSBase,
Misc_WrGSBase,
Misc_XSave,
Misc_XSave64,
Misc_XSaveC,
Misc_XSaveC64,
Misc_XSaveOpt,
Misc_XSaveOpt64,
Misc_XSaveS,
Misc_XSaveS64,
Misc_XRstor,
Misc_XRstor64,
Misc_XRstorS,
Misc_XRstorS64,
Misc_XGetBV,
Misc_XSetBV,
Misc_Monitorx,
Misc_MWaitx,
Misc_Clzero,
Misc_RdPid,
Misc_RdPMC,
Misc_RdTSC,
Misc_RdTSCP,
Misc_Serialize,
Misc_MovDirI32,
Misc_MovDirI64,
Misc_MovDir64B,
Misc_EnqCmd,
Misc_EnqCmds,
Misc_XSusLDTRK,
Misc_XResLDTRK,
Misc_CmpccxAdd,
Misc_AAdd,
Misc_AAnd,
Misc_AOr,
Misc_AXor,
Misc_Lzcnt16,
Misc_Lzcnt32,
Misc_Lzcnt64,
Misc_Popcnt16,
Misc_Popcnt32,
Misc_Popcnt64,
Avx512_AddPS512,
Avx512_AddPD512,
Avx512_SubPS512,
Avx512_SubPD512,
Avx512_MulPS512,
Avx512_MulPD512,
Avx512_DivPS512,
Avx512_DivPD512,
Avx512_SqrtPS512,
Avx512_SqrtPD512,
Avx512_MinPS512,
Avx512_MinPD512,
Avx512_MaxPS512,
Avx512_MaxPD512,
Avx512_AndPS512,
Avx512_AndPD512,
Avx512_AndnPS512,
Avx512_AndnPD512,
Avx512_OrPS512,
Avx512_OrPD512,
Avx512_XorPS512,
Avx512_XorPD512,
Avx512_CmpPS512,
Avx512_CmpPD512,
Avx512_BroadcastSS512,
Avx512_BroadcastSD512,
Avx512_PermilvarPS512,
Avx512_PermilvarPD512,
Avx512_ShufPS512,
Avx512_ShufPD512,
Avx512_UnpcklPS512,
Avx512_UnpckhPS512,
Avx512_UnpcklPD512,
Avx512_UnpckhPD512,
Avx512_ValignQ512,
Avx512_ValignD512,
Avx512_VbroadcastF32x4,
Avx512_VbroadcastF64x2,
Avx512_ShufF32x4,
Avx512_ShufF64x2,
Avx512_ExtractF32x4,
Avx512_ExtractF64x2,
Avx512_InsertF32x4,
Avx512_InsertF64x2,
Avx512_RangePS512,
Avx512_RangePD512,
Avx512_ReducePS512,
Avx512_ReducePD512,
Avx512_GetExpPS512,
Avx512_GetExpPD512,
Avx512_GetMantPS512,
Avx512_GetMantPD512,
Avx512_ScalefPS512,
Avx512_ScalefPD512,
Avx512_RndScalePS512,
Avx512_RndScalePD512,
Avx512_RndScaleSS,
Avx512_RndScaleSD,
Avx512_GetExpSS,
Avx512_GetExpSD,
Avx512_GetMantSS,
Avx512_GetMantSD,
Avx512_ScalefSS,
Avx512_ScalefSD,
Avx512_RangeSS,
Avx512_RangeSD,
Avx512_ReduceSS,
Avx512_ReduceSD,
Avx512_FixupImmPS512,
Avx512_FixupImmPD512,
Avx512_FixupImmSS,
Avx512_FixupImmSD,
Avx512_Rcp14PS512,
Avx512_Rcp14PD512,
Avx512_Rcp14SS,
Avx512_Rcp14SD,
Avx512_Rsqrt14PS512,
Avx512_Rsqrt14PD512,
Avx512_Rsqrt14SS,
Avx512_Rsqrt14SD,
Avx512_ConflictD512,
Avx512_ConflictQ512,
Avx512_Exp2PS512,
Avx512_Exp2PD512,
Avx512_PAddB512,
Avx512_PAddW512,
Avx512_PSubB512,
Avx512_PSubW512,
Avx512_PMulLW512,
Avx512_PMulHW512,
Avx512_PMaddW512,
Avx512_PCmpEqB512,
Avx512_PCmpEqW512,
Avx512_PCmpGtB512,
Avx512_PCmpGtW512,
Avx512_PSllvW512,
Avx512_PSrlvW512,
Avx512_PSravW512,
Avx512_PSllvD512,
Avx512_PSllvQ512,
Avx512_PSrlvD512,
Avx512_PSrlvQ512,
Avx512_PSravD512,
Avx512_PSravQ512,
Avx512_PShufB512,
Avx512_MovDQU8,
Avx512_MovDQU16,
Avx512_PAddD512,
Avx512_PAddQ512,
Avx512_PSubD512,
Avx512_PSubQ512,
Avx512_PMulLD512,
Avx512_PMulQ512,
Avx512_PAndD512,
Avx512_PAndQ512,
Avx512_PAndnD512,
Avx512_PAndnQ512,
Avx512_POrD512,
Avx512_POrQ512,
Avx512_PXorD512,
Avx512_PXorQ512,
Avx512_PMulDQ512,
Avx512_PMulUDQ512,
Avx512_PCmpEQQ512,
Avx512_PCmpGTQ512,
Avx512_PermD512,
Avx512_PermQ512,
Avx512_PSllD512,
Avx512_PSllQ512,
Avx512_PSrlD512,
Avx512_PSrlQ512,
Avx512_PSraD512,
Avx512_PSraQ512,
Avx512_CvtPD2DQ512,
Avx512_CvtPD2UDQ512,
Avx512_CvtPS2DQ512,
Avx512_CvtPS2UDQ512,
Avx512_CvtDQ2PD512,
Avx512_CvtUDQ2PD512,
Avx512_CvtDQ2PS512,
Avx512_CvtUDQ2PS512,
Avx512_CvtTPD2DQ512,
Avx512_CvtTPD2UDQ512,
Avx512_CvtTPS2DQ512,
Avx512_CvtTPS2UDQ512,
Avx512_InsertI32x4VL128,
Avx512_InsertI64x2VL128,
Avx512_InsertI32x4VL256,
Avx512_InsertI64x2VL256,
Avx512_VPMadd52LUQ,
Avx512_VPMadd52HUQ,
Avx512_PermB,
Avx512_PermW,
Avx512_Permi2B,
Avx512_Permi2W,
Avx512_Permt2B,
Avx512_Permt2W,
Avx512_PExpandB,
Avx512_PExpandW,
Avx512_PCompressB,
Avx512_PCompressW,
Avx512_VPDPBUSD,
Avx512_VPDPBUSDS,
Avx512_VPDPWSSD,
Avx512_VPDPWSSDS,
Avx512_VPopcntB,
Avx512_VPopcntW,
Avx512_VPopcntD,
Avx512_VPopcntQ,
Avx512_VPopcntD_DQ,
Avx512_VPopcntQ_DQ,
Avx512_CvtNe2Ps2Bf16,
Avx512_CvtNeEbf162Ps,
Avx512_CvtNeObf162Ps,
Avx512_DPBf16PS,
Avx512_AddPH,
Avx512_SubPH,
Avx512_MulPH,
Avx512_DivPH,
Avx512_MinPH,
Avx512_MaxPH,
Avx512_SqrtPH,
Avx512_RndScalePH,
Avx512_GetMantPH,
Avx512_GetExpPH,
Avx512_ScalefPH,
Avx512_CvtPH2W,
Avx512_CvtW2PH,
Avx512_CvtPH2UW,
Avx512_CvtUW2PH,
Avx512_Fmadd132PH,
Avx512_Fmadd213PH,
Avx512_Fmadd231PH,
Avx512_Fmsub132PH,
Avx512_Fmsub213PH,
Avx512_Fmsub231PH,
Avx512_Fnmadd132PH,
Avx512_Fnmadd213PH,
Avx512_Fnmadd231PH,
Avx512_Fnmsub132PH,
Avx512_Fnmsub213PH,
Avx512_Fnmsub231PH,
Avx512_CmpPH,
Avx512_CvtPH2PS,
Avx512_CvtPS2PH,
Avx512_Fmaddsub132PH,
Avx512_Fmaddsub213PH,
Avx512_Fmaddsub231PH,
Avx512_Fmsubadd132PH,
Avx512_Fmsubadd213PH,
Avx512_Fmsubadd231PH,
Avx512_RcpPH,
Avx512_RsqrtPH,
Avx512_ReducePH,
Avx512_VAesEnc,
Avx512_VAesEncLast,
Avx512_VAesDec,
Avx512_VAesDecLast,
Avx512_VPCLmulQDQ,
Avx512_VGF2P8AffineQB,
Avx512_VGF2P8AffineInvQB,
Avx512_VGF2P8MulB,
Avx512_VP2IntersectD,
Avx512_VP2IntersectQ,
Amx_TileLoadD,
Amx_TileStoreD,
Amx_TileConfig,
Amx_TileRelease,
Amx_TileZero,
Amx_TDPBSSD,
Amx_TDPBSUD,
Amx_TDPBUSD,
Amx_TDPBUUD,
Amx_TDPBF16PS,
Amx_TDPFP16PS,
}
impl X86Intrinsic {
pub const COUNT: usize = 508;
pub fn index(self) -> usize {
self as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum X86IntrinsicGroup {
SSE,
SSE2,
SSE3,
SSSE3,
SSE41,
SSE42,
AVX,
AVX2,
FMA,
BMI,
BMI2,
ADX,
AES,
SHA,
RDRAND,
RDSEED,
CLFLUSHOPT,
LZCNT,
POPCNT,
XSAVE,
MOVDIR,
AVX512F,
AVX512CD,
AVX512ER,
AVX512PF,
AVX512BW,
AVX512DQ,
AVX512VL,
AVX512IFMA,
AVX512VBMI,
AVX512VBMI2,
AVX512VNNI,
AVX512BITALG,
AVX512VPOPCNTDQ,
AVX512BF16,
AVX512FP16,
AVX512VAES,
AVX512GFNI,
AVX512VP2INTERSECT,
AMX,
Misc,
}
impl X86IntrinsicGroup {
pub fn as_str(&self) -> &'static str {
match self {
Self::SSE => "sse",
Self::SSE2 => "sse2",
Self::SSE3 => "sse3",
Self::SSSE3 => "ssse3",
Self::SSE41 => "sse4.1",
Self::SSE42 => "sse4.2",
Self::AVX => "avx",
Self::AVX2 => "avx2",
Self::FMA => "fma",
Self::BMI => "bmi",
Self::BMI2 => "bmi2",
Self::ADX => "adx",
Self::AES => "aes",
Self::SHA => "sha",
Self::RDRAND => "rdrand",
Self::RDSEED => "rdseed",
Self::CLFLUSHOPT => "clflushopt",
Self::LZCNT => "lzcnt",
Self::POPCNT => "popcnt",
Self::XSAVE => "xsave",
Self::MOVDIR => "movdir",
Self::AVX512F => "avx512f",
Self::AVX512CD => "avx512cd",
Self::AVX512ER => "avx512er",
Self::AVX512PF => "avx512pf",
Self::AVX512BW => "avx512bw",
Self::AVX512DQ => "avx512dq",
Self::AVX512VL => "avx512vl",
Self::AVX512IFMA => "avx512ifma",
Self::AVX512VBMI => "avx512vbmi",
Self::AVX512VBMI2 => "avx512vbmi2",
Self::AVX512VNNI => "avx512vnni",
Self::AVX512BITALG => "avx512bitalg",
Self::AVX512VPOPCNTDQ => "avx512vpopcntdq",
Self::AVX512BF16 => "avx512bf16",
Self::AVX512FP16 => "avx512fp16",
Self::AVX512VAES => "avx512vaes",
Self::AVX512GFNI => "avx512gfni",
Self::AVX512VP2INTERSECT => "avx512vp2intersect",
Self::AMX => "amx",
Self::Misc => "misc",
}
}
pub fn feature_flag(&self) -> &'static str {
match self {
Self::SSE => "+sse",
Self::SSE2 => "+sse2",
Self::SSE3 => "+sse3",
Self::SSSE3 => "+ssse3",
Self::SSE41 => "+sse4.1",
Self::SSE42 => "+sse4.2",
Self::AVX => "+avx",
Self::AVX2 => "+avx2",
Self::FMA => "+fma",
Self::BMI => "+bmi",
Self::BMI2 => "+bmi2",
Self::ADX => "+adx",
Self::AES => "+aes",
Self::SHA => "+sha",
Self::RDRAND => "+rdrnd",
Self::RDSEED => "+rdseed",
Self::CLFLUSHOPT => "+clflushopt",
Self::LZCNT => "+lzcnt",
Self::POPCNT => "+popcnt",
Self::XSAVE => "+xsave",
Self::MOVDIR => "+movdiri,+movdir64b",
Self::AVX512F => "+avx512f",
Self::AVX512CD => "+avx512cd",
Self::AVX512ER => "+avx512er",
Self::AVX512PF => "+avx512pf",
Self::AVX512BW => "+avx512bw",
Self::AVX512DQ => "+avx512dq",
Self::AVX512VL => "+avx512vl",
Self::AVX512IFMA => "+avx512ifma",
Self::AVX512VBMI => "+avx512vbmi",
Self::AVX512VBMI2 => "+avx512vbmi2",
Self::AVX512VNNI => "+avx512vnni",
Self::AVX512BITALG => "+avx512bitalg",
Self::AVX512VPOPCNTDQ => "+avx512vpopcntdq",
Self::AVX512BF16 => "+avx512bf16",
Self::AVX512FP16 => "+avx512fp16",
Self::AVX512VAES => "+vaes",
Self::AVX512GFNI => "+gfni",
Self::AVX512VP2INTERSECT => "+avx512vp2intersect",
Self::AMX => "+amx-tile,+amx-int8,+amx-bf16",
Self::Misc => "",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntrinsicSideEffect {
None,
ReadMem,
WriteMem,
ReadWriteMem,
Sync,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct AlignInfo {
pub min_align_bytes: u32,
pub prefer_align_bytes: u32,
}
impl AlignInfo {
pub const NONE: AlignInfo = AlignInfo {
min_align_bytes: 0,
prefer_align_bytes: 0,
};
pub const ALIGN_16: AlignInfo = AlignInfo {
min_align_bytes: 1,
prefer_align_bytes: 16,
};
pub const ALIGN_32: AlignInfo = AlignInfo {
min_align_bytes: 1,
prefer_align_bytes: 32,
};
pub const ALIGN_64: AlignInfo = AlignInfo {
min_align_bytes: 1,
prefer_align_bytes: 64,
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RetTypeDesc {
Void,
I1,
I8,
I16,
I32,
I64,
I128,
F32,
F64,
V2F64,
V4F32,
V8F32,
V16F32,
V2I64,
V4I32,
V8I16,
V16I8,
V4F64,
V8I32,
V16I16,
V32I8,
V8F64,
V16I32,
V32I16,
V64I8,
V4I64,
V8I64,
SameAsOp0,
}
#[derive(Debug, Clone)]
pub struct X86IntrinsicInfo {
pub intrinsic: X86Intrinsic,
pub llvm_name: &'static str,
pub builtin_name: Option<&'static str>,
pub group: X86IntrinsicGroup,
pub num_operands: usize,
pub ret_type: RetTypeDesc,
pub param_types: Vec<RetTypeDesc>,
pub side_effects: IntrinsicSideEffect,
pub align: AlignInfo,
pub is_commutative: bool,
pub has_mask_variant: bool,
pub has_rounding_variant: bool,
pub min_feature: &'static str,
}
impl RetTypeDesc {
pub fn to_type_str(&self) -> &'static str {
match self {
Self::Void => "void",
Self::I1 => "i1",
Self::I8 => "i8",
Self::I16 => "i16",
Self::I32 => "i32",
Self::I64 => "i64",
Self::I128 => "i128",
Self::F32 => "f32",
Self::F64 => "f64",
Self::V2F64 => "<2 x f64>",
Self::V4F32 => "<4 x f32>",
Self::V8F32 => "<8 x f32>",
Self::V16F32 => "<16 x f32>",
Self::V2I64 => "<2 x i64>",
Self::V4I32 => "<4 x i32>",
Self::V8I16 => "<8 x i16>",
Self::V16I8 => "<16 x i8>",
Self::V4F64 => "<4 x f64>",
Self::V8I32 => "<8 x i32>",
Self::V16I16 => "<16 x i16>",
Self::V32I8 => "<32 x i8>",
Self::V8F64 => "<8 x f64>",
Self::V16I32 => "<16 x i32>",
Self::V32I16 => "<32 x i16>",
Self::V64I8 => "<64 x i8>",
Self::V4I64 => "<4 x i64>",
Self::V8I64 => "<8 x i64>",
Self::SameAsOp0 => "<op0>",
}
}
}
pub struct X86IntrinsicTable {
infos: Vec<X86IntrinsicInfo>,
by_name: HashMap<&'static str, usize>,
by_group: HashMap<X86IntrinsicGroup, Vec<usize>>,
}
impl X86IntrinsicTable {
pub fn new() -> Self {
let mut table = Self {
infos: Vec::with_capacity(600),
by_name: HashMap::with_capacity(600),
by_group: HashMap::new(),
};
table.populate();
table
}
fn add(&mut self, info: X86IntrinsicInfo) {
let idx = self.infos.len();
self.by_name.insert(info.llvm_name, idx);
self.by_group.entry(info.group).or_default().push(idx);
self.infos.push(info);
}
fn entry(
intrinsic: X86Intrinsic,
llvm_name: &'static str,
group: X86IntrinsicGroup,
num_operands: usize,
ret_type: RetTypeDesc,
param_types: Vec<RetTypeDesc>,
) -> X86IntrinsicInfo {
X86IntrinsicInfo {
intrinsic,
llvm_name,
builtin_name: None,
group,
num_operands,
ret_type,
param_types,
side_effects: IntrinsicSideEffect::None,
align: AlignInfo::NONE,
is_commutative: false,
has_mask_variant: false,
has_rounding_variant: false,
min_feature: group.feature_flag(),
}
}
fn entry_comm(
intrinsic: X86Intrinsic,
llvm_name: &'static str,
group: X86IntrinsicGroup,
num_operands: usize,
ret_type: RetTypeDesc,
param_types: Vec<RetTypeDesc>,
) -> X86IntrinsicInfo {
let mut info = Self::entry(
intrinsic,
llvm_name,
group,
num_operands,
ret_type,
param_types,
);
info.is_commutative = true;
info
}
fn entry_512(
intrinsic: X86Intrinsic,
llvm_name: &'static str,
group: X86IntrinsicGroup,
num_operands: usize,
ret_type: RetTypeDesc,
param_types: Vec<RetTypeDesc>,
mask: bool,
rnd: bool,
) -> X86IntrinsicInfo {
let mut info = Self::entry(
intrinsic,
llvm_name,
group,
num_operands,
ret_type,
param_types,
);
info.has_mask_variant = mask;
info.has_rounding_variant = rnd;
info
}
fn entry_mem(
intrinsic: X86Intrinsic,
llvm_name: &'static str,
group: X86IntrinsicGroup,
num_operands: usize,
ret_type: RetTypeDesc,
param_types: Vec<RetTypeDesc>,
se: IntrinsicSideEffect,
align: AlignInfo,
) -> X86IntrinsicInfo {
let mut info = Self::entry(
intrinsic,
llvm_name,
group,
num_operands,
ret_type,
param_types,
);
info.side_effects = se;
info.align = align;
info
}
fn populate(&mut self) {
macro_rules! add {
($intr:ident, $name:literal, $g:expr_2021, $n:expr_2021, $ret:ident, [ $($p:ident),* $(,)? ]) => {
self.add(Self::entry(
X86Intrinsic::$intr, $name, $g, $n,
RetTypeDesc::$ret,
vec![$(RetTypeDesc::$p),*],
))
};
}
macro_rules! add_comm {
($intr:ident, $name:literal, $g:expr_2021, $n:expr_2021, $ret:ident, [ $($p:ident),* $(,)? ]) => {
self.add(Self::entry_comm(
X86Intrinsic::$intr, $name, $g, $n,
RetTypeDesc::$ret,
vec![$(RetTypeDesc::$p),*],
))
};
}
macro_rules! add_512 {
($intr:ident, $name:literal, $g:expr_2021, $n:expr_2021, $ret:ident, [ $($p:ident),* $(,)? ], $mask:expr_2021, $rnd:expr_2021) => {
self.add(Self::entry_512(
X86Intrinsic::$intr, $name, $g, $n,
RetTypeDesc::$ret,
vec![$(RetTypeDesc::$p),*],
$mask, $rnd,
))
};
}
macro_rules! add_mem {
($intr:ident, $name:literal, $g:expr_2021, $n:expr_2021, $ret:ident, [ $($p:ident),* $(,)? ], $se:expr_2021, $al:expr_2021) => {
self.add(Self::entry_mem(
X86Intrinsic::$intr, $name, $g, $n,
RetTypeDesc::$ret,
vec![$(RetTypeDesc::$p),*],
$se, $al,
))
};
}
let sse = X86IntrinsicGroup::SSE;
for &(intr, name_str, comm) in &[
(X86Intrinsic::Sse_AddPS, "llvm.x86.sse.add.ps", true),
(X86Intrinsic::Sse_SubPS, "llvm.x86.sse.sub.ps", false),
(X86Intrinsic::Sse_MulPS, "llvm.x86.sse.mul.ps", true),
(X86Intrinsic::Sse_DivPS, "llvm.x86.sse.div.ps", false),
(X86Intrinsic::Sse_MinPS, "llvm.x86.sse.min.ps", true),
(X86Intrinsic::Sse_MaxPS, "llvm.x86.sse.max.ps", true),
] {
let ps = vec![RetTypeDesc::V4F32, RetTypeDesc::V4F32];
if comm {
self.add(Self::entry_comm(
intr,
name_str,
sse,
2,
RetTypeDesc::V4F32,
ps,
));
} else {
self.add(Self::entry(intr, name_str, sse, 2, RetTypeDesc::V4F32, ps));
}
}
for &(intr, name_str, comm) in &[
(X86Intrinsic::Sse_AddSS, "llvm.x86.sse.add.ss", true),
(X86Intrinsic::Sse_SubSS, "llvm.x86.sse.sub.ss", false),
(X86Intrinsic::Sse_MulSS, "llvm.x86.sse.mul.ss", true),
(X86Intrinsic::Sse_DivSS, "llvm.x86.sse.div.ss", false),
(X86Intrinsic::Sse_MinSS, "llvm.x86.sse.min.ss", true),
(X86Intrinsic::Sse_MaxSS, "llvm.x86.sse.max.ss", true),
] {
let ps = vec![RetTypeDesc::V4F32, RetTypeDesc::V4F32];
if comm {
self.add(Self::entry_comm(
intr,
name_str,
sse,
2,
RetTypeDesc::V4F32,
ps,
));
} else {
self.add(Self::entry(intr, name_str, sse, 2, RetTypeDesc::V4F32, ps));
}
}
add!(Sse_SqrtPS, "llvm.x86.sse.sqrt.ps", sse, 1, V4F32, [V4F32]);
add!(
Sse_SqrtSS,
"llvm.x86.sse.sqrt.ss",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(Sse_RcpPS, "llvm.x86.sse.rcp.ps", sse, 1, V4F32, [V4F32]);
add!(
Sse_RcpSS,
"llvm.x86.sse.rcp.ss",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(Sse_RsqrtPS, "llvm.x86.sse.rsqrt.ps", sse, 1, V4F32, [V4F32]);
add!(
Sse_RsqrtSS,
"llvm.x86.sse.rsqrt.ss",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse_CmpPS,
"llvm.x86.sse.cmp.ps",
sse,
3,
V4F32,
[V4F32, V4F32, I8]
);
add!(
Sse_CmpSS,
"llvm.x86.sse.cmp.ss",
sse,
3,
V4F32,
[V4F32, V4F32, I8]
);
add!(
Sse_ComiSS,
"llvm.x86.sse.comieq.ss",
sse,
2,
I32,
[V4F32, V4F32]
);
add!(
Sse_UComiSS,
"llvm.x86.sse.ucomieq.ss",
sse,
2,
I32,
[V4F32, V4F32]
);
add!(Sse_CvtSS2SI, "llvm.x86.sse.cvtss2si", sse, 1, I32, [V4F32]);
add!(
Sse_CvtSS2SI64,
"llvm.x86.sse.cvtss2si64",
sse,
1,
I64,
[V4F32]
);
add!(
Sse_CvttSS2SI,
"llvm.x86.sse.cvttss2si",
sse,
1,
I32,
[V4F32]
);
add!(
Sse_CvttSS2SI64,
"llvm.x86.sse.cvttss2si64",
sse,
1,
I64,
[V4F32]
);
add!(
Sse_CvtSI2SS,
"llvm.x86.sse.cvtsi2ss",
sse,
2,
V4F32,
[V4F32, I32]
);
add!(
Sse_CvtSI642SS,
"llvm.x86.sse.cvtsi642ss",
sse,
2,
V4F32,
[V4F32, I64]
);
add_comm!(
Sse_AndPS,
"llvm.x86.sse.and.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse_AndnPS,
"llvm.x86.sse.andn.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add_comm!(
Sse_OrPS,
"llvm.x86.sse.or.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add_comm!(
Sse_XorPS,
"llvm.x86.sse.xor.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse_MovHLPS,
"llvm.x86.sse.movhl.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse_MovLHPS,
"llvm.x86.sse.movlh.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(Sse_MovMSKPS, "llvm.x86.sse.movmsk.ps", sse, 1, I32, [V4F32]);
add!(
Sse_MovSS,
"llvm.x86.sse.mov.ss",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse_ShufPS,
"llvm.x86.sse.shuf.ps",
sse,
3,
V4F32,
[V4F32, V4F32, I8]
);
add!(
Sse_UnpcklPS,
"llvm.x86.sse.unpckl.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse_UnpckhPS,
"llvm.x86.sse.unpckh.ps",
sse,
2,
V4F32,
[V4F32, V4F32]
);
add_mem!(
Sse_MovntPS,
"llvm.x86.sse.movnt.ps",
sse,
2,
Void,
[I32, V4F32],
IntrinsicSideEffect::WriteMem,
AlignInfo::ALIGN_16
);
add_mem!(
Sse_Prefetch,
"llvm.x86.sse.prefetch",
sse,
2,
Void,
[I8, I32],
IntrinsicSideEffect::ReadWriteMem,
AlignInfo::NONE
);
add!(Sse_Sfence, "llvm.x86.sse.sfence", sse, 0, Void, []);
let sse2 = X86IntrinsicGroup::SSE2;
for &(intr, name_str, comm) in &[
(X86Intrinsic::Sse2_AddPD, "llvm.x86.sse2.add.pd", true),
(X86Intrinsic::Sse2_SubPD, "llvm.x86.sse2.sub.pd", false),
(X86Intrinsic::Sse2_MulPD, "llvm.x86.sse2.mul.pd", true),
(X86Intrinsic::Sse2_DivPD, "llvm.x86.sse2.div.pd", false),
(X86Intrinsic::Sse2_MinPD, "llvm.x86.sse2.min.pd", true),
(X86Intrinsic::Sse2_MaxPD, "llvm.x86.sse2.max.pd", true),
] {
let ps = vec![RetTypeDesc::V2F64, RetTypeDesc::V2F64];
if comm {
self.add(Self::entry_comm(
intr,
name_str,
sse2,
2,
RetTypeDesc::V2F64,
ps,
));
} else {
self.add(Self::entry(intr, name_str, sse2, 2, RetTypeDesc::V2F64, ps));
}
}
for &(intr, name_str, comm) in &[
(X86Intrinsic::Sse2_AddSD, "llvm.x86.sse2.add.sd", true),
(X86Intrinsic::Sse2_SubSD, "llvm.x86.sse2.sub.sd", false),
(X86Intrinsic::Sse2_MulSD, "llvm.x86.sse2.mul.sd", true),
(X86Intrinsic::Sse2_DivSD, "llvm.x86.sse2.div.sd", false),
(X86Intrinsic::Sse2_MinSD, "llvm.x86.sse2.min.sd", true),
(X86Intrinsic::Sse2_MaxSD, "llvm.x86.sse2.max.sd", true),
] {
let ps = vec![RetTypeDesc::V2F64, RetTypeDesc::V2F64];
if comm {
self.add(Self::entry_comm(
intr,
name_str,
sse2,
2,
RetTypeDesc::V2F64,
ps,
));
} else {
self.add(Self::entry(intr, name_str, sse2, 2, RetTypeDesc::V2F64, ps));
}
}
add!(
Sse2_SqrtPD,
"llvm.x86.sse2.sqrt.pd",
sse2,
1,
V2F64,
[V2F64]
);
add!(
Sse2_SqrtSD,
"llvm.x86.sse2.sqrt.sd",
sse2,
2,
V2F64,
[V2F64, V2F64]
);
add_comm!(
Sse2_AndPD,
"llvm.x86.sse2.and.pd",
sse2,
2,
V2F64,
[V2F64, V2F64]
);
add!(
Sse2_AndnPD,
"llvm.x86.sse2.andn.pd",
sse2,
2,
V2F64,
[V2F64, V2F64]
);
add_comm!(
Sse2_OrPD,
"llvm.x86.sse2.or.pd",
sse2,
2,
V2F64,
[V2F64, V2F64]
);
add_comm!(
Sse2_XorPD,
"llvm.x86.sse2.xor.pd",
sse2,
2,
V2F64,
[V2F64, V2F64]
);
add!(
Sse2_CmpPD,
"llvm.x86.sse2.cmp.pd",
sse2,
3,
V2F64,
[V2F64, V2F64, I8]
);
add!(
Sse2_CmpSD,
"llvm.x86.sse2.cmp.sd",
sse2,
3,
V2F64,
[V2F64, V2F64, I8]
);
add!(
Sse2_ComiSD,
"llvm.x86.sse2.comieq.sd",
sse2,
2,
I32,
[V2F64, V2F64]
);
add!(
Sse2_UComiSD,
"llvm.x86.sse2.ucomieq.sd",
sse2,
2,
I32,
[V2F64, V2F64]
);
add!(
Sse2_CvtPD2PS,
"llvm.x86.sse2.cvtpd2ps",
sse2,
1,
V4F32,
[V2F64]
);
add!(
Sse2_CvtPS2PD,
"llvm.x86.sse2.cvtps2pd",
sse2,
1,
V2F64,
[V4F32]
);
add!(
Sse2_CvtPD2DQ,
"llvm.x86.sse2.cvtpd2dq",
sse2,
1,
V4I32,
[V2F64]
);
add!(
Sse2_CvtTPD2DQ,
"llvm.x86.sse2.cvttpd2dq",
sse2,
1,
V4I32,
[V2F64]
);
add!(
Sse2_CvtDQ2PD,
"llvm.x86.sse2.cvtdq2pd",
sse2,
1,
V2F64,
[V4I32]
);
add!(
Sse2_CvtDQ2PS,
"llvm.x86.sse2.cvtdq2ps",
sse2,
1,
V4F32,
[V4I32]
);
add!(
Sse2_CvtPS2DQ,
"llvm.x86.sse2.cvtps2dq",
sse2,
1,
V4I32,
[V4F32]
);
add!(
Sse2_CvtTPS2DQ,
"llvm.x86.sse2.cvttps2dq",
sse2,
1,
V4I32,
[V4F32]
);
add!(
Sse2_CvtSD2SS,
"llvm.x86.sse2.cvtsd2ss",
sse2,
2,
V4F32,
[V4F32, V2F64]
);
add!(
Sse2_CvtSS2SD,
"llvm.x86.sse2.cvtss2sd",
sse2,
2,
V2F64,
[V2F64, V4F32]
);
add!(
Sse2_CvtSD2SI,
"llvm.x86.sse2.cvtsd2si",
sse2,
1,
I32,
[V2F64]
);
add!(
Sse2_CvtSD2SI64,
"llvm.x86.sse2.cvtsd2si64",
sse2,
1,
I64,
[V2F64]
);
add!(
Sse2_CvttSD2SI,
"llvm.x86.sse2.cvttsd2si",
sse2,
1,
I32,
[V2F64]
);
add!(
Sse2_CvttSD2SI64,
"llvm.x86.sse2.cvttsd2si64",
sse2,
1,
I64,
[V2F64]
);
add!(
Sse2_CvtSI2SD,
"llvm.x86.sse2.cvtsi2sd",
sse2,
2,
V2F64,
[V2F64, I32]
);
add!(
Sse2_CvtSI642SD,
"llvm.x86.sse2.cvtsi642sd",
sse2,
2,
V2F64,
[V2F64, I64]
);
for &(intr, name_str) in &[
(X86Intrinsic::Sse2_PAddB, "llvm.x86.sse2.padd.b"),
(X86Intrinsic::Sse2_PAddW, "llvm.x86.sse2.padd.w"),
(X86Intrinsic::Sse2_PAddD, "llvm.x86.sse2.padd.d"),
(X86Intrinsic::Sse2_PSubB, "llvm.x86.sse2.psub.b"),
(X86Intrinsic::Sse2_PSubW, "llvm.x86.sse2.psub.w"),
(X86Intrinsic::Sse2_PSubD, "llvm.x86.sse2.psub.d"),
] {
let ps = vec![RetTypeDesc::V16I8, RetTypeDesc::V16I8];
self.add(Self::entry_comm(
intr,
name_str,
sse2,
2,
RetTypeDesc::V16I8,
ps,
));
}
for &(intr, name_str) in &[
(X86Intrinsic::Sse2_PMulLW, "llvm.x86.sse2.pmull.w"),
(X86Intrinsic::Sse2_PMulHW, "llvm.x86.sse2.pmulh.w"),
] {
let ps = vec![RetTypeDesc::V8I16, RetTypeDesc::V8I16];
self.add(Self::entry_comm(
intr,
name_str,
sse2,
2,
RetTypeDesc::V8I16,
ps,
));
}
add_comm!(
Sse2_PAnd,
"llvm.x86.sse2.pand",
sse2,
2,
V2I64,
[V2I64, V2I64]
);
add!(
Sse2_PAndn,
"llvm.x86.sse2.pandn",
sse2,
2,
V2I64,
[V2I64, V2I64]
);
add_comm!(
Sse2_POr,
"llvm.x86.sse2.por",
sse2,
2,
V2I64,
[V2I64, V2I64]
);
add_comm!(
Sse2_PXor,
"llvm.x86.sse2.pxor",
sse2,
2,
V2I64,
[V2I64, V2I64]
);
add!(
Sse2_PShufD,
"llvm.x86.sse2.pshuf.d",
sse2,
2,
V4I32,
[V4I32, I8]
);
add!(
Sse2_PackSSWB,
"llvm.x86.sse2.packsswb.128",
sse2,
2,
V16I8,
[V8I16, V8I16]
);
add!(
Sse2_PUnpcklBW,
"llvm.x86.sse2.punpcklbw.128",
sse2,
2,
V16I8,
[V16I8, V16I8]
);
add!(
Sse2_PUnpckhBW,
"llvm.x86.sse2.punpckhbw.128",
sse2,
2,
V16I8,
[V16I8, V16I8]
);
add!(
Sse2_PSllW,
"llvm.x86.sse2.psll.w",
sse2,
2,
V8I16,
[V8I16, V8I16]
);
add!(
Sse2_PSllD,
"llvm.x86.sse2.psll.d",
sse2,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Sse2_PSrlW,
"llvm.x86.sse2.psrl.w",
sse2,
2,
V8I16,
[V8I16, V8I16]
);
add!(
Sse2_PSrlD,
"llvm.x86.sse2.psrl.d",
sse2,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Sse2_PSraW,
"llvm.x86.sse2.psra.w",
sse2,
2,
V8I16,
[V8I16, V8I16]
);
add!(
Sse2_PSraD,
"llvm.x86.sse2.psra.d",
sse2,
2,
V4I32,
[V4I32, V4I32]
);
add!(Sse2_LFence, "llvm.x86.sse2.lfence", sse2, 0, Void, []);
add!(Sse2_MFence, "llvm.x86.sse2.mfence", sse2, 0, Void, []);
let sse3 = X86IntrinsicGroup::SSE3;
add!(
Sse3_HAddPS,
"llvm.x86.sse3.hadd.ps",
sse3,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse3_HAddPD,
"llvm.x86.sse3.hadd.pd",
sse3,
2,
V2F64,
[V2F64, V2F64]
);
add!(
Sse3_HSubPS,
"llvm.x86.sse3.hsub.ps",
sse3,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse3_HSubPD,
"llvm.x86.sse3.hsub.pd",
sse3,
2,
V2F64,
[V2F64, V2F64]
);
add!(
Sse3_AddSubPS,
"llvm.x86.sse3.addsub.ps",
sse3,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Sse3_AddSubPD,
"llvm.x86.sse3.addsub.pd",
sse3,
2,
V2F64,
[V2F64, V2F64]
);
add!(
Sse3_MovDDup,
"llvm.x86.sse3.movddup",
sse3,
1,
V2F64,
[V2F64]
);
add!(
Sse3_MovSHDup,
"llvm.x86.sse3.movshdup",
sse3,
1,
V4F32,
[V4F32]
);
add!(
Sse3_MovSLDup,
"llvm.x86.sse3.movsldup",
sse3,
1,
V4F32,
[V4F32]
);
let ssse3 = X86IntrinsicGroup::SSSE3;
add!(
Ssse3_PHAddW,
"llvm.x86.ssse3.phadd.w.128",
ssse3,
2,
V8I16,
[V8I16, V8I16]
);
add!(
Ssse3_PHAddD,
"llvm.x86.ssse3.phadd.d.128",
ssse3,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Ssse3_PShufB,
"llvm.x86.ssse3.pshuf.b.128",
ssse3,
2,
V16I8,
[V16I8, V16I8]
);
add!(
Ssse3_PSignB,
"llvm.x86.ssse3.psign.b.128",
ssse3,
2,
V16I8,
[V16I8, V16I8]
);
add!(
Ssse3_PAbsB,
"llvm.x86.ssse3.pabs.b.128",
ssse3,
1,
V16I8,
[V16I8]
);
add!(
Ssse3_PAbsD,
"llvm.x86.ssse3.pabs.d.128",
ssse3,
1,
V4I32,
[V4I32]
);
let sse41 = X86IntrinsicGroup::SSE41;
add_comm!(
Sse41_PMulLD,
"llvm.x86.sse41.pmulld",
sse41,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Sse41_PMinSB,
"llvm.x86.sse41.pminsb",
sse41,
2,
V16I8,
[V16I8, V16I8]
);
add!(
Sse41_PMaxSB,
"llvm.x86.sse41.pmaxsb",
sse41,
2,
V16I8,
[V16I8, V16I8]
);
add!(
Sse41_PCmpEQQ,
"llvm.x86.sse41.pcmpeqq",
sse41,
2,
V2I64,
[V2I64, V2I64]
);
add!(
Sse41_BlendPS,
"llvm.x86.sse41.blend.ps",
sse41,
3,
V4F32,
[V4F32, V4F32, I8]
);
add!(
Sse41_RoundPS,
"llvm.x86.sse41.round.ps",
sse41,
2,
V4F32,
[V4F32, I32]
);
add!(
Sse41_ExtractPS,
"llvm.x86.sse41.extractps",
sse41,
2,
I32,
[V4F32, I8]
);
add!(
Sse41_InsertPS,
"llvm.x86.sse41.insertps",
sse41,
3,
V4F32,
[V4F32, V4F32, I8]
);
add!(
Sse41_PInsrB,
"llvm.x86.sse41.pinsrb",
sse41,
3,
V16I8,
[V16I8, I32, I8]
);
add!(
Sse41_PExtrB,
"llvm.x86.sse41.pextrb",
sse41,
2,
I32,
[V16I8, I8]
);
add!(
Sse41_PMovSXBD,
"llvm.x86.sse41.pmovsxbd",
sse41,
1,
V4I32,
[V16I8]
);
add!(
Sse41_PMovZXBD,
"llvm.x86.sse41.pmovzxbd",
sse41,
1,
V4I32,
[V16I8]
);
let sse42 = X86IntrinsicGroup::SSE42;
add!(
Sse42_Crc32_8,
"llvm.x86.sse42.crc32.8",
sse42,
2,
I32,
[I32, I8]
);
add!(
Sse42_Crc32_16,
"llvm.x86.sse42.crc32.16",
sse42,
2,
I32,
[I32, I16]
);
add!(
Sse42_Crc32_32,
"llvm.x86.sse42.crc32.32",
sse42,
2,
I32,
[I32, I32]
);
add!(
Sse42_Crc32_64,
"llvm.x86.sse42.crc32.64",
sse42,
2,
I64,
[I64, I64]
);
let aes = X86IntrinsicGroup::AES;
add!(
Aes_AesEnc,
"llvm.x86.aesni.aesenc",
aes,
2,
V2I64,
[V2I64, V2I64]
);
add!(
Aes_AesEncLast,
"llvm.x86.aesni.aesenclast",
aes,
2,
V2I64,
[V2I64, V2I64]
);
add!(
Aes_AesDec,
"llvm.x86.aesni.aesdec",
aes,
2,
V2I64,
[V2I64, V2I64]
);
add!(
Aes_AesDecLast,
"llvm.x86.aesni.aesdeclast",
aes,
2,
V2I64,
[V2I64, V2I64]
);
add!(Aes_AesIMC, "llvm.x86.aesni.aesimc", aes, 1, V2I64, [V2I64]);
add!(
Aes_AesKeyGenAssist,
"llvm.x86.aesni.aeskeygenassist",
aes,
2,
V2I64,
[V2I64, I8]
);
add!(
Aes_PCLmulQDQ,
"llvm.x86.pclmulqdq",
aes,
3,
V2I64,
[V2I64, V2I64, I8]
);
let sha = X86IntrinsicGroup::SHA;
add!(
Sha_Sha1Rnds4,
"llvm.x86.sha1rnds4",
sha,
3,
V4I32,
[V4I32, V4I32, I8]
);
add!(
Sha_Sha1Nexte,
"llvm.x86.sha1nexte",
sha,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Sha_Sha1Msg1,
"llvm.x86.sha1msg1",
sha,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Sha_Sha1Msg2,
"llvm.x86.sha1msg2",
sha,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Sha_Sha256Rnds2,
"llvm.x86.sha256rnds2",
sha,
3,
V4I32,
[V4I32, V4I32, V4I32]
);
add!(
Sha_Sha256Msg1,
"llvm.x86.sha256msg1",
sha,
2,
V4I32,
[V4I32, V4I32]
);
add!(
Sha_Sha256Msg2,
"llvm.x86.sha256msg2",
sha,
2,
V4I32,
[V4I32, V4I32]
);
add!(
RdRand16,
"llvm.x86.rdrand.16",
X86IntrinsicGroup::RDRAND,
0,
I16,
[]
);
add!(
RdRand32,
"llvm.x86.rdrand.32",
X86IntrinsicGroup::RDRAND,
0,
I32,
[]
);
add!(
RdRand64,
"llvm.x86.rdrand.64",
X86IntrinsicGroup::RDRAND,
0,
I64,
[]
);
add!(
RdSeed16,
"llvm.x86.rdseed.16",
X86IntrinsicGroup::RDSEED,
0,
I16,
[]
);
add!(
RdSeed32,
"llvm.x86.rdseed.32",
X86IntrinsicGroup::RDSEED,
0,
I32,
[]
);
add!(
RdSeed64,
"llvm.x86.rdseed.64",
X86IntrinsicGroup::RDSEED,
0,
I64,
[]
);
let avx = X86IntrinsicGroup::AVX;
add_comm!(
Avx_AddPS256,
"llvm.x86.avx.add.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add_comm!(
Avx_AddPD256,
"llvm.x86.avx.add.pd.256",
avx,
2,
V4F64,
[V4F64, V4F64]
);
add!(
Avx_SubPS256,
"llvm.x86.avx.sub.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add!(
Avx_SubPD256,
"llvm.x86.avx.sub.pd.256",
avx,
2,
V4F64,
[V4F64, V4F64]
);
add_comm!(
Avx_MulPS256,
"llvm.x86.avx.mul.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add_comm!(
Avx_MulPD256,
"llvm.x86.avx.mul.pd.256",
avx,
2,
V4F64,
[V4F64, V4F64]
);
add!(
Avx_DivPS256,
"llvm.x86.avx.div.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add!(
Avx_DivPD256,
"llvm.x86.avx.div.pd.256",
avx,
2,
V4F64,
[V4F64, V4F64]
);
add_comm!(
Avx_MinPS256,
"llvm.x86.avx.min.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add_comm!(
Avx_MaxPS256,
"llvm.x86.avx.max.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add!(
Avx_AddSS,
"llvm.x86.avx.add.ss",
avx,
2,
V4F32,
[V4F32, V4F32]
);
add!(
Avx_AddSD,
"llvm.x86.avx.add.sd",
avx,
2,
V2F64,
[V2F64, V2F64]
);
add_comm!(
Avx_AndPS256,
"llvm.x86.avx.and.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add_comm!(
Avx_OrPS256,
"llvm.x86.avx.or.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add_comm!(
Avx_XorPS256,
"llvm.x86.avx.xor.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add!(
Avx_BroadcastSS,
"llvm.x86.avx.vbroadcast.ss",
avx,
1,
V4F32,
[I32]
);
add!(
Avx_BroadcastSD,
"llvm.x86.avx.vbroadcast.sd",
avx,
1,
V2F64,
[I32]
);
add!(
Avx_Perm2F128,
"llvm.x86.avx.vperm2f128.ps.256",
avx,
3,
V8F32,
[V8F32, V8F32, I8]
);
add!(Avx_ZeroAll, "llvm.x86.avx.vzeroall", avx, 0, Void, []);
add!(Avx_ZeroUpper, "llvm.x86.avx.vzeroupper", avx, 0, Void, []);
add!(
Avx_HAddPS256,
"llvm.x86.avx.hadd.ps.256",
avx,
2,
V8F32,
[V8F32, V8F32]
);
add!(
Avx_ShufPS256,
"llvm.x86.avx.shuf.ps.256",
avx,
3,
V8F32,
[V8F32, V8F32, I8]
);
let avx2 = X86IntrinsicGroup::AVX2;
add_comm!(
Avx2_PAddB256,
"llvm.x86.avx2.padd.b.256",
avx2,
2,
V32I8,
[V32I8, V32I8]
);
add_comm!(
Avx2_PAddW256,
"llvm.x86.avx2.padd.w.256",
avx2,
2,
V16I16,
[V16I16, V16I16]
);
add_comm!(
Avx2_PAddD256,
"llvm.x86.avx2.padd.d.256",
avx2,
2,
V8I32,
[V8I32, V8I32]
);
add_comm!(
Avx2_PMulLD256,
"llvm.x86.avx2.pmulld.256",
avx2,
2,
V8I32,
[V8I32, V8I32]
);
add_comm!(
Avx2_PAnd256,
"llvm.x86.avx2.pand.256",
avx2,
2,
V4I64,
[V4I64, V4I64]
);
add_comm!(
Avx2_POr256,
"llvm.x86.avx2.por.256",
avx2,
2,
V4I64,
[V4I64, V4I64]
);
add_comm!(
Avx2_PXor256,
"llvm.x86.avx2.pxor.256",
avx2,
2,
V4I64,
[V4I64, V4I64]
);
add!(
Avx2_PSllvD256,
"llvm.x86.avx2.psllv.d.256",
avx2,
2,
V8I32,
[V8I32, V8I32]
);
add!(
Avx2_PSllvQ256,
"llvm.x86.avx2.psllv.q.256",
avx2,
2,
V4I64,
[V4I64, V4I64]
);
add!(
Avx2_PSrlvD256,
"llvm.x86.avx2.psrlv.d.256",
avx2,
2,
V8I32,
[V8I32, V8I32]
);
add!(
Avx2_PSravD256,
"llvm.x86.avx2.psrav.d.256",
avx2,
2,
V8I32,
[V8I32, V8I32]
);
add_mem!(
Avx2_GatherDPS,
"llvm.x86.avx2.gather.d.ps.256",
avx2,
5,
V8F32,
[V8F32, I32, V8I32, V8F32, I8],
IntrinsicSideEffect::ReadMem,
AlignInfo::ALIGN_32
);
add_mem!(
Avx2_GatherDD,
"llvm.x86.avx2.gather.d.d.256",
avx2,
5,
V8I32,
[V8I32, I32, V8I32, V8I32, I8],
IntrinsicSideEffect::ReadMem,
AlignInfo::ALIGN_32
);
let fma = X86IntrinsicGroup::FMA;
for &(intr, name_str) in &[
(X86Intrinsic::Fma_Fmadd132PS, "llvm.x86.fma.fmadd.132.ps"),
(X86Intrinsic::Fma_Fmadd213PS, "llvm.x86.fma.fmadd.213.ps"),
(X86Intrinsic::Fma_Fmadd231PS, "llvm.x86.fma.fmadd.231.ps"),
(X86Intrinsic::Fma_Fmsub132PS, "llvm.x86.fma.fmsub.132.ps"),
(X86Intrinsic::Fma_Fmsub213PS, "llvm.x86.fma.fmsub.213.ps"),
(X86Intrinsic::Fma_Fmsub231PS, "llvm.x86.fma.fmsub.231.ps"),
(X86Intrinsic::Fma_Fnmadd132PS, "llvm.x86.fma.fnmadd.132.ps"),
(X86Intrinsic::Fma_Fnmadd213PS, "llvm.x86.fma.fnmadd.213.ps"),
(X86Intrinsic::Fma_Fnmadd231PS, "llvm.x86.fma.fnmadd.231.ps"),
(X86Intrinsic::Fma_Fnmsub132PS, "llvm.x86.fma.fnmsub.132.ps"),
(X86Intrinsic::Fma_Fnmsub213PS, "llvm.x86.fma.fnmsub.213.ps"),
(X86Intrinsic::Fma_Fnmsub231PS, "llvm.x86.fma.fnmsub.231.ps"),
] {
let ps = vec![RetTypeDesc::V4F32, RetTypeDesc::V4F32, RetTypeDesc::V4F32];
self.add(Self::entry(intr, name_str, fma, 3, RetTypeDesc::V4F32, ps));
}
for &(intr, name_str) in &[
(X86Intrinsic::Fma_Fmadd132PD, "llvm.x86.fma.fmadd.132.pd"),
(X86Intrinsic::Fma_Fmadd213PD, "llvm.x86.fma.fmadd.213.pd"),
(X86Intrinsic::Fma_Fmadd231PD, "llvm.x86.fma.fmadd.231.pd"),
] {
let ps = vec![RetTypeDesc::V2F64, RetTypeDesc::V2F64, RetTypeDesc::V2F64];
self.add(Self::entry(intr, name_str, fma, 3, RetTypeDesc::V2F64, ps));
}
self.add(Self::entry(
X86Intrinsic::Fma_Fmadd132SS,
"llvm.x86.fma.fmadd.132.ss",
fma,
3,
RetTypeDesc::V4F32,
vec![RetTypeDesc::V4F32, RetTypeDesc::V4F32, RetTypeDesc::V4F32],
));
self.add(Self::entry(
X86Intrinsic::Fma_Fmadd132SD,
"llvm.x86.fma.fmadd.132.sd",
fma,
3,
RetTypeDesc::V2F64,
vec![RetTypeDesc::V2F64, RetTypeDesc::V2F64, RetTypeDesc::V2F64],
));
let bmi = X86IntrinsicGroup::BMI;
add!(Bmi_Andn32, "llvm.x86.bmi.andn.32", bmi, 2, I32, [I32, I32]);
add!(
Bmi_Bextr32,
"llvm.x86.bmi.bextr.32",
bmi,
2,
I32,
[I32, I32]
);
add!(Bmi_Blsi32, "llvm.x86.bmi.blsi.32", bmi, 1, I32, [I32]);
add!(Bmi_Blsmsk32, "llvm.x86.bmi.blsmsk.32", bmi, 1, I32, [I32]);
add!(Bmi_Blsr32, "llvm.x86.bmi.blsr.32", bmi, 1, I32, [I32]);
add!(Bmi_Tzcnt16, "llvm.x86.bmi.tzcnt.16", bmi, 1, I16, [I16]);
add!(Bmi_Tzcnt32, "llvm.x86.bmi.tzcnt.32", bmi, 1, I32, [I32]);
add!(Bmi_Tzcnt64, "llvm.x86.bmi.tzcnt.64", bmi, 1, I64, [I64]);
let bmi2 = X86IntrinsicGroup::BMI2;
for &(intr, name_str) in &[
(X86Intrinsic::Bmi2_Bzhi32, "llvm.x86.bmi2.bzhi.32"),
(X86Intrinsic::Bmi2_Mulx32, "llvm.x86.bmi2.mulx.32"),
(X86Intrinsic::Bmi2_Pdep32, "llvm.x86.bmi2.pdep.32"),
(X86Intrinsic::Bmi2_Pext32, "llvm.x86.bmi2.pext.32"),
(X86Intrinsic::Bmi2_Rorx32, "llvm.x86.bmi2.rorx.32"),
(X86Intrinsic::Bmi2_Sarx32, "llvm.x86.bmi2.sarx.32"),
(X86Intrinsic::Bmi2_Shlx32, "llvm.x86.bmi2.shlx.32"),
(X86Intrinsic::Bmi2_Shrx32, "llvm.x86.bmi2.shrx.32"),
] {
let ps = vec![RetTypeDesc::I32, RetTypeDesc::I32];
self.add(Self::entry(intr, name_str, bmi2, 2, RetTypeDesc::I32, ps));
}
for &(intr, name_str) in &[
(X86Intrinsic::Bmi2_Bzhi64, "llvm.x86.bmi2.bzhi.64"),
(X86Intrinsic::Bmi2_Mulx64, "llvm.x86.bmi2.mulx.64"),
(X86Intrinsic::Bmi2_Pdep64, "llvm.x86.bmi2.pdep.64"),
(X86Intrinsic::Bmi2_Pext64, "llvm.x86.bmi2.pext.64"),
(X86Intrinsic::Bmi2_Rorx64, "llvm.x86.bmi2.rorx.64"),
(X86Intrinsic::Bmi2_Sarx64, "llvm.x86.bmi2.sarx.64"),
(X86Intrinsic::Bmi2_Shlx64, "llvm.x86.bmi2.shlx.64"),
(X86Intrinsic::Bmi2_Shrx64, "llvm.x86.bmi2.shrx.64"),
] {
let ps = vec![RetTypeDesc::I64, RetTypeDesc::I64];
self.add(Self::entry(intr, name_str, bmi2, 2, RetTypeDesc::I64, ps));
}
let adx = X86IntrinsicGroup::ADX;
add!(Adx_Adcx32, "llvm.x86.adx.adcx.32", adx, 2, I8, [I32, I32]);
add!(Adx_Adcx64, "llvm.x86.adx.adcx.64", adx, 2, I8, [I64, I64]);
add!(Adx_Adox32, "llvm.x86.adx.adox.32", adx, 2, I8, [I32, I32]);
add!(Adx_Adox64, "llvm.x86.adx.adox.64", adx, 2, I8, [I64, I64]);
add_mem!(
Misc_Clflushopt,
"llvm.x86.clflushopt",
X86IntrinsicGroup::CLFLUSHOPT,
1,
Void,
[I8],
IntrinsicSideEffect::ReadWriteMem,
AlignInfo::NONE
);
add_mem!(
Misc_XSave,
"llvm.x86.xsave",
X86IntrinsicGroup::XSAVE,
2,
Void,
[I32, I32],
IntrinsicSideEffect::WriteMem,
AlignInfo::ALIGN_64
);
add_mem!(
Misc_XRstor,
"llvm.x86.xrstor",
X86IntrinsicGroup::XSAVE,
2,
Void,
[I32, I32],
IntrinsicSideEffect::ReadMem,
AlignInfo::ALIGN_64
);
add_mem!(
Misc_Monitorx,
"llvm.x86.monitorx",
X86IntrinsicGroup::Misc,
3,
Void,
[I32, I32, I32],
IntrinsicSideEffect::ReadWriteMem,
AlignInfo::NONE
);
add_mem!(
Misc_MWaitx,
"llvm.x86.mwaitx",
X86IntrinsicGroup::Misc,
4,
Void,
[I32, I32, I32, I32],
IntrinsicSideEffect::ReadWriteMem,
AlignInfo::NONE
);
add_mem!(
Misc_Clzero,
"llvm.x86.clzero",
X86IntrinsicGroup::Misc,
0,
Void,
[],
IntrinsicSideEffect::WriteMem,
AlignInfo::ALIGN_64
);
add!(
Misc_RdTSC,
"llvm.x86.rdtsc",
X86IntrinsicGroup::Misc,
0,
I64,
[]
);
add!(
Misc_RdTSCP,
"llvm.x86.rdtscp",
X86IntrinsicGroup::Misc,
1,
I64,
[I32]
);
add!(
Misc_Lzcnt16,
"llvm.x86.lzcnt.16",
X86IntrinsicGroup::LZCNT,
1,
I16,
[I16]
);
add!(
Misc_Lzcnt32,
"llvm.x86.lzcnt.32",
X86IntrinsicGroup::LZCNT,
1,
I32,
[I32]
);
add!(
Misc_Lzcnt64,
"llvm.x86.lzcnt.64",
X86IntrinsicGroup::LZCNT,
1,
I64,
[I64]
);
add!(
Misc_Popcnt16,
"llvm.x86.popcnt.16",
X86IntrinsicGroup::POPCNT,
1,
I16,
[I16]
);
add!(
Misc_Popcnt32,
"llvm.x86.popcnt.32",
X86IntrinsicGroup::POPCNT,
1,
I32,
[I32]
);
add!(
Misc_Popcnt64,
"llvm.x86.popcnt.64",
X86IntrinsicGroup::POPCNT,
1,
I64,
[I64]
);
let avx512f = X86IntrinsicGroup::AVX512F;
add_512!(
Avx512_AddPS512,
"llvm.x86.avx512.add.ps.512",
avx512f,
2,
V16F32,
[V16F32, V16F32],
true,
true
);
add_512!(
Avx512_AddPD512,
"llvm.x86.avx512.add.pd.512",
avx512f,
2,
V8F64,
[V8F64, V8F64],
true,
true
);
add_512!(
Avx512_SubPS512,
"llvm.x86.avx512.sub.ps.512",
avx512f,
2,
V16F32,
[V16F32, V16F32],
true,
true
);
add_512!(
Avx512_MulPS512,
"llvm.x86.avx512.mul.ps.512",
avx512f,
2,
V16F32,
[V16F32, V16F32],
true,
true
);
add_512!(
Avx512_MulPD512,
"llvm.x86.avx512.mul.pd.512",
avx512f,
2,
V8F64,
[V8F64, V8F64],
true,
true
);
add_512!(
Avx512_DivPS512,
"llvm.x86.avx512.div.ps.512",
avx512f,
2,
V16F32,
[V16F32, V16F32],
true,
true
);
add_512!(
Avx512_DivPD512,
"llvm.x86.avx512.div.pd.512",
avx512f,
2,
V8F64,
[V8F64, V8F64],
true,
true
);
add_512!(
Avx512_MinPS512,
"llvm.x86.avx512.min.ps.512",
avx512f,
2,
V16F32,
[V16F32, V16F32],
true,
false
);
add_512!(
Avx512_MaxPS512,
"llvm.x86.avx512.max.ps.512",
avx512f,
2,
V16F32,
[V16F32, V16F32],
true,
false
);
add_512!(
Avx512_RndScalePS512,
"llvm.x86.avx512.rndscale.ps.512",
avx512f,
3,
V16F32,
[V16F32, I32, I32],
true,
true
);
add_512!(
Avx512_Rcp14PS512,
"llvm.x86.avx512.rcp14.ps.512",
avx512f,
1,
V16F32,
[V16F32],
true,
false
);
add_512!(
Avx512_Rsqrt14PS512,
"llvm.x86.avx512.rsqrt14.ps.512",
avx512f,
1,
V16F32,
[V16F32],
true,
false
);
add_512!(
Avx512_FixupImmPS512,
"llvm.x86.avx512.fixupimm.ps.512",
avx512f,
4,
V16F32,
[V16F32, V16F32, V16I32, I32],
true,
true
);
let avx512dq = X86IntrinsicGroup::AVX512DQ;
add_512!(
Avx512_PAddD512,
"llvm.x86.avx512.padd.d.512",
avx512dq,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_PAddQ512,
"llvm.x86.avx512.padd.q.512",
avx512dq,
2,
V8I64,
[V8I64, V8I64],
true,
false
);
add_512!(
Avx512_PMulLD512,
"llvm.x86.avx512.pmulld.512",
avx512dq,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_PMulDQ512,
"llvm.x86.avx512.pmuldq.512",
avx512dq,
2,
V8I64,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_PCmpEQQ512,
"llvm.x86.avx512.pcmpeqq.512",
avx512dq,
2,
V8I64,
[V8I64, V8I64],
true,
false
);
add_512!(
Avx512_PAndD512,
"llvm.x86.avx512.pand.d.512",
avx512dq,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_POrD512,
"llvm.x86.avx512.por.d.512",
avx512dq,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_PXorD512,
"llvm.x86.avx512.pxor.d.512",
avx512dq,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
let avx512bw = X86IntrinsicGroup::AVX512BW;
add_512!(
Avx512_PAddB512,
"llvm.x86.avx512.padd.b.512",
avx512bw,
2,
V64I8,
[V64I8, V64I8],
true,
false
);
add_512!(
Avx512_PAddW512,
"llvm.x86.avx512.padd.w.512",
avx512bw,
2,
V32I16,
[V32I16, V32I16],
true,
false
);
add_512!(
Avx512_PSllvD512,
"llvm.x86.avx512.psllv.d.512",
avx512bw,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_PSrlvD512,
"llvm.x86.avx512.psrlv.d.512",
avx512bw,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_VPDPBUSD,
"llvm.x86.avx512.vpdpbusd.512",
X86IntrinsicGroup::AVX512VNNI,
3,
V16I32,
[V16I32, V16I32, V16I32],
true,
false
);
add_512!(
Avx512_VPDPWSSD,
"llvm.x86.avx512.vpdpwssd.512",
X86IntrinsicGroup::AVX512VNNI,
3,
V16I32,
[V16I32, V16I32, V16I32],
true,
false
);
add_512!(
Avx512_VPMadd52LUQ,
"llvm.x86.avx512.vpmadd52luq.512",
X86IntrinsicGroup::AVX512IFMA,
3,
V8I64,
[V8I64, V8I64, V8I64],
true,
false
);
add_512!(
Avx512_VPMadd52HUQ,
"llvm.x86.avx512.vpmadd52huq.512",
X86IntrinsicGroup::AVX512IFMA,
3,
V8I64,
[V8I64, V8I64, V8I64],
true,
false
);
add_512!(
Avx512_VGF2P8AffineQB,
"llvm.x86.vgf2p8affineqb.512",
X86IntrinsicGroup::AVX512GFNI,
3,
V64I8,
[V64I8, V64I8, I8],
true,
false
);
add_512!(
Avx512_VGF2P8AffineInvQB,
"llvm.x86.vgf2p8affineinvqb.512",
X86IntrinsicGroup::AVX512GFNI,
3,
V64I8,
[V64I8, V64I8, I8],
true,
false
);
add_512!(
Avx512_VGF2P8MulB,
"llvm.x86.vgf2p8mulb.512",
X86IntrinsicGroup::AVX512GFNI,
2,
V64I8,
[V64I8, V64I8],
true,
false
);
add!(
Avx512_VAesEnc,
"llvm.x86.vaesenc.512",
X86IntrinsicGroup::AVX512VAES,
2,
V64I8,
[V64I8, V64I8]
);
add!(
Avx512_VAesEncLast,
"llvm.x86.vaesenclast.512",
X86IntrinsicGroup::AVX512VAES,
2,
V64I8,
[V64I8, V64I8]
);
add!(
Avx512_VAesDec,
"llvm.x86.vaesdec.512",
X86IntrinsicGroup::AVX512VAES,
2,
V64I8,
[V64I8, V64I8]
);
add!(
Avx512_VAesDecLast,
"llvm.x86.vaesdeclast.512",
X86IntrinsicGroup::AVX512VAES,
2,
V64I8,
[V64I8, V64I8]
);
let avx512fp16 = X86IntrinsicGroup::AVX512FP16;
add_512!(
Avx512_AddPH,
"llvm.x86.avx512fp16.add.ph.512",
avx512fp16,
2,
V32I16,
[V32I16, V32I16],
true,
false
);
add_512!(
Avx512_MulPH,
"llvm.x86.avx512fp16.mul.ph.512",
avx512fp16,
2,
V32I16,
[V32I16, V32I16],
true,
false
);
add_512!(
Avx512_MinPH,
"llvm.x86.avx512fp16.min.ph.512",
avx512fp16,
2,
V32I16,
[V32I16, V32I16],
true,
false
);
add_512!(
Avx512_MaxPH,
"llvm.x86.avx512fp16.max.ph.512",
avx512fp16,
2,
V32I16,
[V32I16, V32I16],
true,
false
);
add_512!(
Avx512_VPopcntB,
"llvm.x86.avx512.mask.vpopcnt.b.512",
X86IntrinsicGroup::AVX512BITALG,
1,
V64I8,
[V64I8],
true,
false
);
add_512!(
Avx512_VPopcntD,
"llvm.x86.avx512.mask.vpopcnt.d.512",
X86IntrinsicGroup::AVX512BITALG,
1,
V16I32,
[V16I32],
true,
false
);
add_512!(
Avx512_CvtNe2Ps2Bf16,
"llvm.x86.avx512bf16.cvtne2ps2bf16.512",
X86IntrinsicGroup::AVX512BF16,
2,
V16I32,
[V16I32, V16I32],
true,
false
);
add_512!(
Avx512_DPBf16PS,
"llvm.x86.avx512bf16.dpbf16ps.512",
X86IntrinsicGroup::AVX512BF16,
3,
V16F32,
[V16F32, V16I16, V16I16],
true,
false
);
add!(
Avx512_VP2IntersectD,
"llvm.x86.avx512.vp2intersect.d.512",
X86IntrinsicGroup::AVX512VP2INTERSECT,
2,
Void,
[V16I32, V16I32]
);
add!(
Avx512_VP2IntersectQ,
"llvm.x86.avx512.vp2intersect.q.512",
X86IntrinsicGroup::AVX512VP2INTERSECT,
2,
Void,
[V8I64, V8I64]
);
let amx = X86IntrinsicGroup::AMX;
add_mem!(
Amx_TileLoadD,
"llvm.x86.tileloadd64.internal",
amx,
3,
Void,
[I16, I16, I32],
IntrinsicSideEffect::ReadWriteMem,
AlignInfo::NONE
);
add_mem!(
Amx_TileStoreD,
"llvm.x86.tilestored64.internal",
amx,
3,
Void,
[I16, I16, I32],
IntrinsicSideEffect::ReadWriteMem,
AlignInfo::NONE
);
add_mem!(
Amx_TileConfig,
"llvm.x86.tileconfig",
amx,
1,
Void,
[I32],
IntrinsicSideEffect::WriteMem,
AlignInfo::ALIGN_64
);
add!(Amx_TileRelease, "llvm.x86.tilerelease", amx, 0, Void, []);
add!(
Amx_TileZero,
"llvm.x86.tilezero.internal",
amx,
2,
Void,
[I16, I16]
);
add!(
Amx_TDPBSSD,
"llvm.x86.tdpbssd.internal",
amx,
5,
Void,
[I16, I16, I16, I16, I16]
);
add!(
Amx_TDPBF16PS,
"llvm.x86.tdpbf16ps.internal",
amx,
5,
Void,
[I16, I16, I16, I16, I16]
);
self.fill_remaining();
}
fn fill_remaining(&mut self) {
let mut present: Vec<bool> = vec![false; X86Intrinsic::COUNT];
for info in &self.infos {
if info.intrinsic.index() < present.len() {
present[info.intrinsic.index()] = true;
}
}
for variant_idx in 0..X86Intrinsic::COUNT {
if !present[variant_idx] {
let intr: X86Intrinsic = unsafe { std::mem::transmute(variant_idx as u16) };
let group = self.guess_group(intr);
let name = Box::leak(format!("llvm.x86.{:?}.auto", intr).into_boxed_str());
self.add(X86IntrinsicInfo {
intrinsic: intr,
llvm_name: name,
builtin_name: None,
group,
num_operands: 2,
ret_type: RetTypeDesc::V4I32,
param_types: vec![RetTypeDesc::V4I32, RetTypeDesc::V4I32],
side_effects: IntrinsicSideEffect::None,
align: AlignInfo::NONE,
is_commutative: false,
has_mask_variant: false,
has_rounding_variant: false,
min_feature: group.feature_flag(),
});
}
}
}
fn guess_group(&self, intr: X86Intrinsic) -> X86IntrinsicGroup {
use X86Intrinsic::*;
let i = intr.index();
if i <= Sse_PshufW.index() {
return X86IntrinsicGroup::SSE;
}
if i <= Sse2_MaskmovDQU.index() {
return X86IntrinsicGroup::SSE2;
}
if i <= Sse3_MWait.index() {
return X86IntrinsicGroup::SSE3;
}
if i <= Ssse3_PAlignr.index() {
return X86IntrinsicGroup::SSSE3;
}
if i <= Sse41_PMovZXWQ.index() {
return X86IntrinsicGroup::SSE41;
}
if i <= Sse42_Popcnt.index() {
return X86IntrinsicGroup::SSE42;
}
if i <= Aes_PCLmulQDQ.index() {
return X86IntrinsicGroup::AES;
}
if i <= Sha_Sha256Msg2.index() {
return X86IntrinsicGroup::SHA;
}
if i <= RdSeed64.index() {
return X86IntrinsicGroup::RDSEED;
}
if i <= Avx_MovntDQ256.index() {
return X86IntrinsicGroup::AVX;
}
if i <= Avx2_PShufD256.index() {
return X86IntrinsicGroup::AVX2;
}
if i <= Fma_Fmsubadd231PD256.index() {
return X86IntrinsicGroup::FMA;
}
if i <= Bmi_Tzcnt64.index() {
return X86IntrinsicGroup::BMI;
}
if i <= Bmi2_Shrx64.index() {
return X86IntrinsicGroup::BMI2;
}
if i <= Adx_Adox64.index() {
return X86IntrinsicGroup::ADX;
}
if i <= Misc_Popcnt64.index() {
return X86IntrinsicGroup::Misc;
}
if i <= Avx512_Rsqrt14SD.index() {
return X86IntrinsicGroup::AVX512F;
}
if i <= Avx512_ConflictQ512.index() {
return X86IntrinsicGroup::AVX512CD;
}
if i <= Avx512_Exp2PD512.index() {
return X86IntrinsicGroup::AVX512ER;
}
if i <= Avx512_MovDQU16.index() {
return X86IntrinsicGroup::AVX512BW;
}
if i <= Avx512_CvtTPS2UDQ512.index() {
return X86IntrinsicGroup::AVX512DQ;
}
if i <= Avx512_InsertI64x2VL256.index() {
return X86IntrinsicGroup::AVX512VL;
}
if i <= Avx512_VPMadd52HUQ.index() {
return X86IntrinsicGroup::AVX512IFMA;
}
if i <= Avx512_Permt2W.index() {
return X86IntrinsicGroup::AVX512VBMI;
}
if i <= Avx512_PCompressW.index() {
return X86IntrinsicGroup::AVX512VBMI2;
}
if i <= Avx512_VPDPWSSDS.index() {
return X86IntrinsicGroup::AVX512VNNI;
}
if i <= Avx512_VPopcntQ.index() {
return X86IntrinsicGroup::AVX512BITALG;
}
if i <= Avx512_VPopcntQ_DQ.index() {
return X86IntrinsicGroup::AVX512VPOPCNTDQ;
}
if i <= Avx512_DPBf16PS.index() {
return X86IntrinsicGroup::AVX512BF16;
}
if i <= Avx512_ReducePH.index() {
return X86IntrinsicGroup::AVX512FP16;
}
if i <= Avx512_VPCLmulQDQ.index() {
return X86IntrinsicGroup::AVX512VAES;
}
if i <= Avx512_VGF2P8MulB.index() {
return X86IntrinsicGroup::AVX512GFNI;
}
if i <= Avx512_VP2IntersectQ.index() {
return X86IntrinsicGroup::AVX512VP2INTERSECT;
}
X86IntrinsicGroup::AMX
}
pub fn lookup(&self, name: &str) -> Option<&X86IntrinsicInfo> {
self.by_name.get(name).map(|&idx| &self.infos[idx])
}
pub fn lookup_by_enum(&self, intr: X86Intrinsic) -> Option<&X86IntrinsicInfo> {
let idx = intr.index();
if idx < self.infos.len() {
Some(&self.infos[idx])
} else {
None
}
}
pub fn by_group(&self, group: X86IntrinsicGroup) -> Vec<&X86IntrinsicInfo> {
self.by_group
.get(&group)
.map(|indices| indices.iter().map(|&i| &self.infos[i]).collect())
.unwrap_or_default()
}
pub fn len(&self) -> usize {
self.infos.len()
}
pub fn is_empty(&self) -> bool {
self.infos.is_empty()
}
pub fn all(&self) -> &[X86IntrinsicInfo] {
&self.infos
}
pub fn count_in_group(&self, group: X86IntrinsicGroup) -> usize {
self.by_group.get(&group).map(|v| v.len()).unwrap_or(0)
}
}
impl Default for X86IntrinsicTable {
fn default() -> Self {
Self::new()
}
}
pub struct X86IntrinsicEmitter {
table: X86IntrinsicTable,
builtin_to_intrinsic: HashMap<String, X86Intrinsic>,
}
impl X86IntrinsicEmitter {
pub fn new() -> Self {
let table = X86IntrinsicTable::new();
let mut b2i = HashMap::new();
for info in table.all() {
if let Some(bn) = info.builtin_name {
b2i.insert(bn.to_string(), info.intrinsic);
}
}
Self {
table,
builtin_to_intrinsic: b2i,
}
}
pub fn emit_name_for_builtin(&self, builtin: &str) -> Option<&'static str> {
self.builtin_to_intrinsic
.get(builtin)
.and_then(|intr| self.table.lookup_by_enum(*intr))
.map(|info| info.llvm_name)
}
pub fn emit_call(&self, intr: X86Intrinsic, args: &[String]) -> String {
if let Some(info) = self.table.lookup_by_enum(intr) {
let ret = info.ret_type.to_type_str();
let params: Vec<&str> = info.param_types.iter().map(|t| t.to_type_str()).collect();
let mut s = format!("{} @{}(", ret, info.llvm_name);
for (i, p) in params.iter().enumerate() {
if i > 0 {
s.push_str(", ");
}
s.push_str(p);
s.push(' ');
s.push_str(args.get(i).map(|a| a.as_str()).unwrap_or("undef"));
}
s.push(')');
s
} else {
format!("; unknown intrinsic {:?}", intr)
}
}
pub fn table(&self) -> &X86IntrinsicTable {
&self.table
}
pub fn builtin_map(&self) -> &HashMap<String, X86Intrinsic> {
&self.builtin_to_intrinsic
}
}
impl Default for X86IntrinsicEmitter {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Verdict {
Valid,
Invalid { reason: String },
}
pub struct X86IntrinsicVerifier {
table: X86IntrinsicTable,
available_features: Vec<String>,
is_64bit: bool,
}
impl X86IntrinsicVerifier {
pub fn new(features: Vec<String>, is_64bit: bool) -> Self {
Self {
table: X86IntrinsicTable::new(),
available_features: features,
is_64bit,
}
}
fn has_feature(&self, flag: &str) -> bool {
if flag.is_empty() {
return true;
}
for f in flag.split(',') {
let f = f.trim();
if !self.available_features.iter().any(|avail| avail == f) {
return false;
}
}
true
}
pub fn verify_operand_count(&self, intr: X86Intrinsic, count: usize) -> Verdict {
let info = match self.table.lookup_by_enum(intr) {
Some(i) => i,
None => {
return Verdict::Invalid {
reason: "unknown intrinsic".into(),
}
}
};
if count != info.num_operands {
Verdict::Invalid {
reason: format!(
"expected {} operands, got {} for {}",
info.num_operands, count, info.llvm_name
),
}
} else {
Verdict::Valid
}
}
pub fn verify_feature(&self, intr: X86Intrinsic) -> Verdict {
let info = match self.table.lookup_by_enum(intr) {
Some(i) => i,
None => {
return Verdict::Invalid {
reason: "unknown intrinsic".into(),
}
}
};
if !self.has_feature(info.min_feature) {
Verdict::Invalid {
reason: format!("{} requires feature `{}`", info.llvm_name, info.min_feature),
}
} else {
Verdict::Valid
}
}
pub fn verify_64bit_mode(&self, intr: X86Intrinsic) -> Verdict {
let name = self
.table
.lookup_by_enum(intr)
.map(|i| i.llvm_name)
.unwrap_or("");
let requires_64 =
name.contains("si64") || name.contains("rdrand.64") || name.contains("rdseed.64");
if requires_64 && !self.is_64bit {
Verdict::Invalid {
reason: format!("{} requires 64-bit mode", name),
}
} else {
Verdict::Valid
}
}
pub fn verify(&self, intr: X86Intrinsic, operand_count: usize) -> Verdict {
for check in [
self.verify_operand_count(intr, operand_count),
self.verify_feature(intr),
self.verify_64bit_mode(intr),
]
.iter()
{
if *check != Verdict::Valid {
return check.clone();
}
}
Verdict::Valid
}
pub fn table(&self) -> &X86IntrinsicTable {
&self.table
}
pub fn features(&self) -> &[String] {
&self.available_features
}
}
impl Default for X86IntrinsicVerifier {
fn default() -> Self {
Self::new(vec!["+sse2".into()], true)
}
}
pub struct X86IntrinsicLowering {
table: X86IntrinsicTable,
}
impl X86IntrinsicLowering {
pub fn new() -> Self {
Self {
table: X86IntrinsicTable::new(),
}
}
pub fn lower_to_opcode(&self, intr: X86Intrinsic) -> Option<X86Opcode> {
use X86Intrinsic::*;
match intr {
Sse_AddPS => Some(X86Opcode::ADDPS),
Sse_AddSS => Some(X86Opcode::ADDSS),
Sse_SubPS => Some(X86Opcode::SUBPS),
Sse_SubSS => Some(X86Opcode::SUBSS),
Sse_MulPS => Some(X86Opcode::MULPS),
Sse_MulSS => Some(X86Opcode::MULSS),
Sse_DivPS => Some(X86Opcode::DIVPS),
Sse_DivSS => Some(X86Opcode::DIVSS),
Sse_MinPS => Some(X86Opcode::MINSS),
Sse_MaxPS => Some(X86Opcode::MAXSS),
Sse_SqrtPS => Some(X86Opcode::SQRTPS),
Sse_SqrtSS => Some(X86Opcode::SQRTSS),
Sse_RcpPS => Some(X86Opcode::RCPPS),
Sse_RsqrtPS => Some(X86Opcode::RSQRTPS),
Sse_AndPS => Some(X86Opcode::ANDPS),
Sse_AndnPS => Some(X86Opcode::ANDNPS),
Sse_OrPS => Some(X86Opcode::ORPS),
Sse_XorPS => Some(X86Opcode::XORPS),
Sse_CmpPS => Some(X86Opcode::CMPSS),
Sse_ShufPS => Some(X86Opcode::SHUFPS),
Sse_UnpcklPS => Some(X86Opcode::UNPCKLPS),
Sse_UnpckhPS => Some(X86Opcode::UNPCKHPS),
Sse_MovSS => Some(X86Opcode::MOVSS),
Sse_MovHLPS => Some(X86Opcode::MOVHLPS),
Sse_MovLHPS => Some(X86Opcode::MOVLHPS),
Sse_CvtSI2SS => Some(X86Opcode::CVTSI2SS),
Sse_CvtSS2SI => Some(X86Opcode::CVTSS2SI),
Sse_CvttSS2SI => Some(X86Opcode::CVTTSS2SI),
Sse_Sfence => Some(X86Opcode::SFENCE),
Sse2_AddPD => Some(X86Opcode::ADDPD),
Sse2_AddSD => Some(X86Opcode::ADDSD),
Sse2_SubPD => Some(X86Opcode::SUBPD),
Sse2_SubSD => Some(X86Opcode::SUBSD),
Sse2_MulPD => Some(X86Opcode::MULPD),
Sse2_MulSD => Some(X86Opcode::MULSD),
Sse2_DivPD => Some(X86Opcode::DIVPD),
Sse2_DivSD => Some(X86Opcode::DIVSD),
Sse2_SqrtPD => Some(X86Opcode::SQRTPS),
Sse2_SqrtSD => Some(X86Opcode::SQRTSD),
Sse2_AndPD => Some(X86Opcode::ANDPD),
Sse2_AndnPD => Some(X86Opcode::ANDNPD),
Sse2_OrPD => Some(X86Opcode::ORPD),
Sse2_XorPD => Some(X86Opcode::XORPD),
Sse2_CmpPD => Some(X86Opcode::CMPSD),
Sse2_CvtPD2PS => Some(X86Opcode::CVTDQ2PS),
Sse2_CvtPS2PD => Some(X86Opcode::CVTDQ2PS),
Sse2_CvtPS2DQ => Some(X86Opcode::CVTPS2DQ),
Sse2_CvtTPS2DQ => Some(X86Opcode::CVTTPS2DQ),
Sse2_CvtSD2SS => Some(X86Opcode::CVTSD2SS),
Sse2_CvtSS2SD => Some(X86Opcode::CVTSS2SD),
Sse2_CvtSD2SI => Some(X86Opcode::CVTSD2SI),
Sse2_CvttSD2SI => Some(X86Opcode::CVTTSD2SI),
Sse2_CvtSI2SD => Some(X86Opcode::CVTSI2SD),
Sse2_MovDQA => Some(X86Opcode::MOVDQA),
Sse2_MovDQU => Some(X86Opcode::MOVDQU),
Sse2_ShufPD => Some(X86Opcode::SHUFPD),
Sse2_UnpcklPD => Some(X86Opcode::UNPCKLPD),
Sse2_UnpckhPD => Some(X86Opcode::UNPCKHPD),
Sse2_PShufD => Some(X86Opcode::PSHUFD),
Sse2_PAnd => Some(X86Opcode::ANDPS),
Sse2_PAndn => Some(X86Opcode::ANDNPS),
Sse2_POr => Some(X86Opcode::ORPS),
Sse2_PXor => Some(X86Opcode::XORPS),
Sse2_PUnpcklBW => Some(X86Opcode::PUNPCKLBW),
Sse2_PUnpcklWD => Some(X86Opcode::PUNPCKLWD),
Sse2_PUnpcklDQ => Some(X86Opcode::PUNPCKLDQ),
Sse2_PUnpcklQDQ => Some(X86Opcode::PUNPCKLQDQ),
Sse2_PUnpckhBW => Some(X86Opcode::PUNPCKHBW),
Sse2_PUnpckhWD => Some(X86Opcode::PUNPCKHWD),
Sse2_PUnpckhDQ => Some(X86Opcode::PUNPCKHDQ),
Sse2_PUnpckhQDQ => Some(X86Opcode::PUNPCKHQDQ),
Sse2_LFence => Some(X86Opcode::LFENCE),
Sse2_MFence => Some(X86Opcode::MFENCE),
Sse3_HAddPS => Some(X86Opcode::HADDPS),
Sse3_HAddPD => Some(X86Opcode::HADDPD),
Sse3_HSubPS => Some(X86Opcode::HSUBPS),
Sse3_HSubPD => Some(X86Opcode::HSUBPD),
Sse3_AddSubPS => Some(X86Opcode::ADDSUBPS),
Sse3_AddSubPD => Some(X86Opcode::ADDSUBPD),
Sse3_MovDDup => Some(X86Opcode::MOVDDUP),
Sse3_MovSHDup => Some(X86Opcode::MOVSHDUP),
Sse3_MovSLDup => Some(X86Opcode::MOVSLDUP),
Ssse3_PHAddW => Some(X86Opcode::PHADDW),
Ssse3_PHAddD => Some(X86Opcode::PHADDD),
Ssse3_PHAddSW => Some(X86Opcode::PHADDSW),
Ssse3_PHSubW => Some(X86Opcode::PHSUBW),
Ssse3_PHSubD => Some(X86Opcode::PHSUBD),
Ssse3_PHSubSW => Some(X86Opcode::PHSUBSW),
Ssse3_PMaddUBSW => Some(X86Opcode::PMADDUBSW),
Ssse3_PSignB => Some(X86Opcode::PSIGNB),
Ssse3_PSignW => Some(X86Opcode::PSIGNW),
Ssse3_PSignD => Some(X86Opcode::PSIGND),
Ssse3_PAbsB => Some(X86Opcode::PABSB),
Ssse3_PAbsW => Some(X86Opcode::PABSW),
Ssse3_PAbsD => Some(X86Opcode::PABSD),
Sse41_PMulLD => Some(X86Opcode::PMULLD),
Sse41_PMulDQ => Some(X86Opcode::PMULDQ),
Sse41_PMinSB => Some(X86Opcode::PMINSB),
Sse41_PMinSD => Some(X86Opcode::PMINSD),
Sse41_PMinUW => Some(X86Opcode::PMINUW),
Sse41_PMinUD => Some(X86Opcode::PMINUD),
Sse41_PMaxSB => Some(X86Opcode::PMAXSB),
Sse41_PMaxSD => Some(X86Opcode::PMAXSD),
Sse41_PMaxUW => Some(X86Opcode::PMAXUW),
Sse41_PMaxUD => Some(X86Opcode::PMAXUD),
Sse41_BlendPS => Some(X86Opcode::BLENDPS),
Sse41_BlendPD => Some(X86Opcode::BLENDPD),
Sse41_BlendvPS => Some(X86Opcode::BLENDVPS),
Sse41_BlendvPD => Some(X86Opcode::BLENDVPD),
Sse41_DppS => Some(X86Opcode::DPPS),
Sse41_DppD => Some(X86Opcode::DPPD),
Sse41_RoundPS => Some(X86Opcode::ROUNDPS),
Sse41_RoundPD => Some(X86Opcode::ROUNDPD),
Sse41_ExtractPS => Some(X86Opcode::EXTRACTPS),
Sse41_InsertPS => Some(X86Opcode::INSERTPS),
Sse41_PackUSDW => Some(X86Opcode::PACKUSDW),
Sse41_PCmpEQQ => Some(X86Opcode::PCMPEQQ),
Sse41_PInsrB => Some(X86Opcode::PINSRB),
Sse41_PInsrW => Some(X86Opcode::PINSRW),
Sse41_PInsrD => Some(X86Opcode::PINSRD),
Sse41_PInsrQ => Some(X86Opcode::PINSRQ),
Sse41_PExtrB => Some(X86Opcode::PEXTRB),
Sse41_PExtrW => Some(X86Opcode::PEXTRW),
Sse41_PExtrD => Some(X86Opcode::PEXTRD),
Sse41_PExtrQ => Some(X86Opcode::PEXTRQ),
Sse42_Crc32_8 | Sse42_Crc32_16 | Sse42_Crc32_32 | Sse42_Crc32_64 => {
Some(X86Opcode::CRC32)
}
Aes_AesEnc => Some(X86Opcode::AESENC),
Aes_AesEncLast => Some(X86Opcode::AESENCLAST),
Aes_AesDec => Some(X86Opcode::AESDEC),
Aes_AesDecLast => Some(X86Opcode::AESDECLAST),
Aes_AesIMC => Some(X86Opcode::AESIMC),
Aes_AesKeyGenAssist => Some(X86Opcode::AESKEYGENASSIST),
Aes_PCLmulQDQ => Some(X86Opcode::PCLMULQDQ),
Sha_Sha1Rnds4 => Some(X86Opcode::SHA1RNDS4),
Sha_Sha1Nexte => Some(X86Opcode::SHA1NEXTE),
Sha_Sha1Msg1 => Some(X86Opcode::SHA1MSG1),
Sha_Sha1Msg2 => Some(X86Opcode::SHA1MSG2),
Sha_Sha256Rnds2 => Some(X86Opcode::SHA256RNDS2),
Sha_Sha256Msg1 => Some(X86Opcode::SHA256MSG1),
Sha_Sha256Msg2 => Some(X86Opcode::SHA256MSG2),
RdRand16 => Some(X86Opcode::RDRAND16),
RdRand32 => Some(X86Opcode::RDRAND32),
RdRand64 => Some(X86Opcode::RDRAND64),
RdSeed16 => Some(X86Opcode::RDSEED16),
RdSeed32 => Some(X86Opcode::RDSEED32),
RdSeed64 => Some(X86Opcode::RDSEED64),
Avx_AddPS256 => Some(X86Opcode::VADDPS),
Avx_AddPD256 => Some(X86Opcode::VADDPD),
Avx_SubPS256 => Some(X86Opcode::VSUBPS),
Avx_SubPD256 => Some(X86Opcode::VSUBPD),
Avx_MulPS256 => Some(X86Opcode::VMULPS),
Avx_MulPD256 => Some(X86Opcode::VMULPD),
Avx_DivPS256 => Some(X86Opcode::VDIVPS),
Avx_DivPD256 => Some(X86Opcode::VDIVPD),
Avx_AddSS => Some(X86Opcode::VADDSS),
Avx_AddSD => Some(X86Opcode::VADDSD),
Avx_AndPS256 => Some(X86Opcode::VANDPS),
Avx_AndnPS256 => Some(X86Opcode::VANDNPS),
Avx_OrPS256 => Some(X86Opcode::VORPS),
Avx_XorPS256 => Some(X86Opcode::VXORPS),
Avx_BroadcastSS => Some(X86Opcode::VBROADCASTSS),
Avx_BroadcastSD => Some(X86Opcode::VBROADCASTSD),
Avx_Perm2F128 => Some(X86Opcode::VPERM2F128),
Avx_ZeroAll => Some(X86Opcode::VZEROALL),
Avx_ZeroUpper => Some(X86Opcode::VZEROUPPER),
Avx2_GatherDPS | Avx2_GatherDD => Some(X86Opcode::VPGATHERDD),
Avx2_GatherDPD => Some(X86Opcode::VPGATHERDQ),
Fma_Fmadd132PS => Some(X86Opcode::VFMADD132PS),
Fma_Fmadd213PS => Some(X86Opcode::VFMADD213PS),
Fma_Fmadd231PS => Some(X86Opcode::VFMADD231PS),
Fma_Fmadd132PD => Some(X86Opcode::VFMADD132PD),
Fma_Fmadd213PD => Some(X86Opcode::VFMADD213PD),
Fma_Fmadd231PD => Some(X86Opcode::VFMADD231PD),
Bmi_Andn32 | Bmi_Andn64 => Some(X86Opcode::ANDN),
Bmi_Bextr32 | Bmi_Bextr64 => Some(X86Opcode::BEXTR),
Bmi_Blsi32 | Bmi_Blsi64 => Some(X86Opcode::BLSI),
Bmi_Blsmsk32 | Bmi_Blsmsk64 => Some(X86Opcode::BLSMSK),
Bmi_Blsr32 | Bmi_Blsr64 => Some(X86Opcode::BLSR),
Bmi_Tzcnt16 | Bmi_Tzcnt32 | Bmi_Tzcnt64 => Some(X86Opcode::TZCNT),
Bmi2_Bzhi32 | Bmi2_Bzhi64 => Some(X86Opcode::BZHI),
Bmi2_Mulx32 | Bmi2_Mulx64 => Some(X86Opcode::MULX),
Bmi2_Pdep32 | Bmi2_Pdep64 => Some(X86Opcode::PDEP),
Bmi2_Pext32 | Bmi2_Pext64 => Some(X86Opcode::PEXT),
Bmi2_Rorx32 | Bmi2_Rorx64 => Some(X86Opcode::RORX),
Bmi2_Sarx32 | Bmi2_Sarx64 => Some(X86Opcode::SARX),
Bmi2_Shlx32 | Bmi2_Shlx64 => Some(X86Opcode::SHLX),
Bmi2_Shrx32 | Bmi2_Shrx64 => Some(X86Opcode::SHRX),
Misc_Clflushopt => Some(X86Opcode::CLFLUSHOPT),
Misc_Clwb => Some(X86Opcode::CLWB),
Misc_Monitorx => Some(X86Opcode::MONITORX_AMD),
Misc_MWaitx => Some(X86Opcode::MWAITX_AMD),
Misc_Clzero => Some(X86Opcode::CLZERO),
Misc_RdTSC => Some(X86Opcode::RDTSC),
Misc_RdTSCP => Some(X86Opcode::RDTSCP),
Misc_PrefetchW => Some(X86Opcode::PREFETCHW),
Misc_PrefetchWt1 => Some(X86Opcode::PREFETCHWT1),
Misc_Lzcnt16 => Some(X86Opcode::LZCNT16),
Misc_Lzcnt32 => Some(X86Opcode::LZCNT32),
Misc_Lzcnt64 => Some(X86Opcode::LZCNT64),
Misc_Popcnt16 => Some(X86Opcode::POPCNT16),
Misc_Popcnt32 => Some(X86Opcode::POPCNT32),
Misc_Popcnt64 => Some(X86Opcode::POPCNT64),
Avx512_AddPS512 => Some(X86Opcode::VADDPS_Z),
Avx512_AddPD512 => Some(X86Opcode::VADDPD_Z),
Avx512_MulPS512 => Some(X86Opcode::VMULPS_Z),
Avx512_MulPD512 => Some(X86Opcode::VMULPD_Z),
Avx512_DivPS512 => Some(X86Opcode::VDIVPS_Z),
Avx512_DivPD512 => Some(X86Opcode::VDIVPD_Z),
Avx512_PAddD512 => Some(X86Opcode::VPADDD_Z),
Avx512_PMulLD512 => Some(X86Opcode::VPMULLD_Z),
Avx512_PAddB512 => Some(X86Opcode::VPADDB_Z),
Avx512_PAddW512 => Some(X86Opcode::VPADDW_Z),
Avx512_VPMadd52LUQ => Some(X86Opcode::VPMADD52LUQ),
Avx512_VPMadd52HUQ => Some(X86Opcode::VPMADD52HUQ),
Avx512_VPDPBUSD => Some(X86Opcode::VPDPBUSD),
Avx512_VPDPWSSD => Some(X86Opcode::VPDPWSSD),
Avx512_VGF2P8AffineQB => Some(X86Opcode::VGF2P8AFFINEQB),
Avx512_VGF2P8AffineInvQB => Some(X86Opcode::VGF2P8AFFINEINVQB),
Avx512_VGF2P8MulB => Some(X86Opcode::VGF2P8MULB),
Avx512_VAesEnc => Some(X86Opcode::VAESENC),
Avx512_VAesEncLast => Some(X86Opcode::VAESENCLAST),
Avx512_VAesDec => Some(X86Opcode::VAESDEC),
Avx512_VAesDecLast => Some(X86Opcode::VAESDECLAST),
Avx512_VPCLmulQDQ => Some(X86Opcode::VPCLMULQDQ),
Avx512_VP2IntersectD => Some(X86Opcode::VP2INTERSECTD),
Avx512_VP2IntersectQ => Some(X86Opcode::VP2INTERSECTQ),
Avx512_DPBf16PS => Some(X86Opcode::VDPBF16PS_Z),
Avx512_CvtNe2Ps2Bf16 => Some(X86Opcode::VCVTNE2PS2BF16_Z),
Amx_TileLoadD => Some(X86Opcode::TILELOADD_Z),
Amx_TileStoreD => Some(X86Opcode::TILESTORED_Z),
Amx_TileConfig => Some(X86Opcode::TILECONFIG),
Amx_TileRelease => Some(X86Opcode::TILERELEASE),
Amx_TileZero => Some(X86Opcode::TILEZERO_Z),
Amx_TDPBSSD => Some(X86Opcode::TDPBSSD_Z),
Amx_TDPBF16PS => Some(X86Opcode::TDPBF16PS_Z),
_ => None,
}
}
pub fn can_expand_inline(&self, intr: X86Intrinsic) -> bool {
matches!(
intr,
X86Intrinsic::Avx_ZeroAll
| X86Intrinsic::Avx_ZeroUpper
| X86Intrinsic::Misc_Monitorx
| X86Intrinsic::Misc_MWaitx
| X86Intrinsic::Misc_Clzero
| X86Intrinsic::Amx_TileConfig
| X86Intrinsic::Amx_TileRelease
)
}
pub fn group_of(&self, intr: X86Intrinsic) -> Option<X86IntrinsicGroup> {
self.table.lookup_by_enum(intr).map(|i| i.group)
}
pub fn table(&self) -> &X86IntrinsicTable {
&self.table
}
}
impl Default for X86IntrinsicLowering {
fn default() -> Self {
Self::new()
}
}
pub static INTRINSIC_OPCODE_TABLE: &[(X86Intrinsic, Option<X86Opcode>)] = &[
(X86Intrinsic::Sse_AddPS, Some(X86Opcode::ADDPS)),
(X86Intrinsic::Sse_AddSS, Some(X86Opcode::ADDSS)),
(X86Intrinsic::Sse_SubPS, Some(X86Opcode::SUBPS)),
(X86Intrinsic::Sse_SubSS, Some(X86Opcode::SUBSS)),
(X86Intrinsic::Sse_MulPS, Some(X86Opcode::MULPS)),
(X86Intrinsic::Sse_MulSS, Some(X86Opcode::MULSS)),
(X86Intrinsic::Sse_DivPS, Some(X86Opcode::DIVPS)),
(X86Intrinsic::Sse_DivSS, Some(X86Opcode::DIVSS)),
(X86Intrinsic::Sse_MinPS, Some(X86Opcode::MINSS)),
(X86Intrinsic::Sse_MaxPS, Some(X86Opcode::MAXSS)),
(X86Intrinsic::Sse_SqrtPS, Some(X86Opcode::SQRTPS)),
(X86Intrinsic::Sse_RcpPS, Some(X86Opcode::RCPPS)),
(X86Intrinsic::Sse_RsqrtPS, Some(X86Opcode::RSQRTPS)),
(X86Intrinsic::Sse_AndPS, Some(X86Opcode::ANDPS)),
(X86Intrinsic::Sse_AndnPS, Some(X86Opcode::ANDNPS)),
(X86Intrinsic::Sse_OrPS, Some(X86Opcode::ORPS)),
(X86Intrinsic::Sse_XorPS, Some(X86Opcode::XORPS)),
(X86Intrinsic::Sse_Sfence, Some(X86Opcode::SFENCE)),
(X86Intrinsic::Sse_CvtSS2SI, Some(X86Opcode::CVTSS2SI)),
(X86Intrinsic::Sse_CvttSS2SI, Some(X86Opcode::CVTTSS2SI)),
(X86Intrinsic::Sse_CvtSI2SS, Some(X86Opcode::CVTSI2SS)),
(X86Intrinsic::Sse_ShufPS, Some(X86Opcode::SHUFPS)),
(X86Intrinsic::Sse_UnpcklPS, Some(X86Opcode::UNPCKLPS)),
(X86Intrinsic::Sse_UnpckhPS, Some(X86Opcode::UNPCKHPS)),
(X86Intrinsic::Sse_MovHLPS, Some(X86Opcode::MOVHLPS)),
(X86Intrinsic::Sse_MovLHPS, Some(X86Opcode::MOVLHPS)),
(X86Intrinsic::Sse_MovSS, Some(X86Opcode::MOVSS)),
(X86Intrinsic::Sse_CmpPS, Some(X86Opcode::CMPSS)),
(X86Intrinsic::Sse2_AddPD, Some(X86Opcode::ADDPD)),
(X86Intrinsic::Sse2_SubPD, Some(X86Opcode::SUBPD)),
(X86Intrinsic::Sse2_MulPD, Some(X86Opcode::MULPD)),
(X86Intrinsic::Sse2_DivPD, Some(X86Opcode::DIVPD)),
(X86Intrinsic::Sse2_AddSD, Some(X86Opcode::ADDSD)),
(X86Intrinsic::Sse2_SubSD, Some(X86Opcode::SUBSD)),
(X86Intrinsic::Sse2_MulSD, Some(X86Opcode::MULSD)),
(X86Intrinsic::Sse2_DivSD, Some(X86Opcode::DIVSD)),
(X86Intrinsic::Sse2_SqrtPD, Some(X86Opcode::SQRTPS)),
(X86Intrinsic::Sse2_SqrtSD, Some(X86Opcode::SQRTSD)),
(X86Intrinsic::Sse2_AndPD, Some(X86Opcode::ANDPD)),
(X86Intrinsic::Sse2_AndnPD, Some(X86Opcode::ANDNPD)),
(X86Intrinsic::Sse2_OrPD, Some(X86Opcode::ORPD)),
(X86Intrinsic::Sse2_XorPD, Some(X86Opcode::XORPD)),
(X86Intrinsic::Sse2_CmpPD, Some(X86Opcode::CMPSD)),
(X86Intrinsic::Sse2_CvtSD2SS, Some(X86Opcode::CVTSD2SS)),
(X86Intrinsic::Sse2_CvtSS2SD, Some(X86Opcode::CVTSS2SD)),
(X86Intrinsic::Sse2_CvtSD2SI, Some(X86Opcode::CVTSD2SI)),
(X86Intrinsic::Sse2_CvttSD2SI, Some(X86Opcode::CVTTSD2SI)),
(X86Intrinsic::Sse2_CvtSI2SD, Some(X86Opcode::CVTSI2SD)),
(X86Intrinsic::Sse2_CvtPS2DQ, Some(X86Opcode::CVTPS2DQ)),
(X86Intrinsic::Sse2_CvtTPS2DQ, Some(X86Opcode::CVTTPS2DQ)),
(X86Intrinsic::Sse2_MovDQA, Some(X86Opcode::MOVDQA)),
(X86Intrinsic::Sse2_MovDQU, Some(X86Opcode::MOVDQU)),
(X86Intrinsic::Sse2_PShufD, Some(X86Opcode::PSHUFD)),
(X86Intrinsic::Sse2_ShufPD, Some(X86Opcode::SHUFPD)),
(X86Intrinsic::Sse2_UnpcklPD, Some(X86Opcode::UNPCKLPD)),
(X86Intrinsic::Sse2_UnpckhPD, Some(X86Opcode::UNPCKHPD)),
(X86Intrinsic::Sse2_PUnpcklBW, Some(X86Opcode::PUNPCKLBW)),
(X86Intrinsic::Sse2_PUnpckhBW, Some(X86Opcode::PUNPCKHBW)),
(X86Intrinsic::Sse2_PUnpcklWD, Some(X86Opcode::PUNPCKLWD)),
(X86Intrinsic::Sse2_PUnpckhWD, Some(X86Opcode::PUNPCKHWD)),
(X86Intrinsic::Sse2_PUnpcklDQ, Some(X86Opcode::PUNPCKLDQ)),
(X86Intrinsic::Sse2_PUnpckhDQ, Some(X86Opcode::PUNPCKHDQ)),
(X86Intrinsic::Sse2_PUnpcklQDQ, Some(X86Opcode::PUNPCKLQDQ)),
(X86Intrinsic::Sse2_PUnpckhQDQ, Some(X86Opcode::PUNPCKHQDQ)),
(X86Intrinsic::Sse2_LFence, Some(X86Opcode::LFENCE)),
(X86Intrinsic::Sse2_MFence, Some(X86Opcode::MFENCE)),
(X86Intrinsic::Sse3_HAddPS, Some(X86Opcode::HADDPS)),
(X86Intrinsic::Sse3_HSubPS, Some(X86Opcode::HSUBPS)),
(X86Intrinsic::Sse3_HAddPD, Some(X86Opcode::HADDPD)),
(X86Intrinsic::Sse3_HSubPD, Some(X86Opcode::HSUBPD)),
(X86Intrinsic::Sse3_AddSubPS, Some(X86Opcode::ADDSUBPS)),
(X86Intrinsic::Sse3_AddSubPD, Some(X86Opcode::ADDSUBPD)),
(X86Intrinsic::Sse3_MovDDup, Some(X86Opcode::MOVDDUP)),
(X86Intrinsic::Sse3_MovSHDup, Some(X86Opcode::MOVSHDUP)),
(X86Intrinsic::Sse3_MovSLDup, Some(X86Opcode::MOVSLDUP)),
(X86Intrinsic::Ssse3_PHAddW, Some(X86Opcode::PHADDW)),
(X86Intrinsic::Ssse3_PHAddD, Some(X86Opcode::PHADDD)),
(X86Intrinsic::Ssse3_PHAddSW, Some(X86Opcode::PHADDSW)),
(X86Intrinsic::Ssse3_PHSubW, Some(X86Opcode::PHSUBW)),
(X86Intrinsic::Ssse3_PHSubD, Some(X86Opcode::PHSUBD)),
(X86Intrinsic::Ssse3_PHSubSW, Some(X86Opcode::PHSUBSW)),
(X86Intrinsic::Ssse3_PMaddUBSW, Some(X86Opcode::PMADDUBSW)),
(X86Intrinsic::Ssse3_PSignB, Some(X86Opcode::PSIGNB)),
(X86Intrinsic::Ssse3_PSignW, Some(X86Opcode::PSIGNW)),
(X86Intrinsic::Ssse3_PSignD, Some(X86Opcode::PSIGND)),
(X86Intrinsic::Ssse3_PAbsB, Some(X86Opcode::PABSB)),
(X86Intrinsic::Ssse3_PAbsW, Some(X86Opcode::PABSW)),
(X86Intrinsic::Ssse3_PAbsD, Some(X86Opcode::PABSD)),
(X86Intrinsic::Sse41_PMulLD, Some(X86Opcode::PMULLD)),
(X86Intrinsic::Sse41_PMulDQ, Some(X86Opcode::PMULDQ)),
(X86Intrinsic::Sse41_PMinSB, Some(X86Opcode::PMINSB)),
(X86Intrinsic::Sse41_PMaxSB, Some(X86Opcode::PMAXSB)),
(X86Intrinsic::Sse41_PMinSD, Some(X86Opcode::PMINSD)),
(X86Intrinsic::Sse41_PMaxSD, Some(X86Opcode::PMAXSD)),
(X86Intrinsic::Sse41_PMinUW, Some(X86Opcode::PMINUW)),
(X86Intrinsic::Sse41_PMaxUW, Some(X86Opcode::PMAXUW)),
(X86Intrinsic::Sse41_PMinUD, Some(X86Opcode::PMINUD)),
(X86Intrinsic::Sse41_PMaxUD, Some(X86Opcode::PMAXUD)),
(X86Intrinsic::Sse41_BlendPS, Some(X86Opcode::BLENDPS)),
(X86Intrinsic::Sse41_BlendPD, Some(X86Opcode::BLENDPD)),
(X86Intrinsic::Sse41_BlendvPS, Some(X86Opcode::BLENDVPS)),
(X86Intrinsic::Sse41_BlendvPD, Some(X86Opcode::BLENDVPD)),
(X86Intrinsic::Sse41_DppS, Some(X86Opcode::DPPS)),
(X86Intrinsic::Sse41_DppD, Some(X86Opcode::DPPD)),
(X86Intrinsic::Sse41_RoundPS, Some(X86Opcode::ROUNDPS)),
(X86Intrinsic::Sse41_RoundPD, Some(X86Opcode::ROUNDPD)),
(X86Intrinsic::Sse41_ExtractPS, Some(X86Opcode::EXTRACTPS)),
(X86Intrinsic::Sse41_InsertPS, Some(X86Opcode::INSERTPS)),
(X86Intrinsic::Sse41_PackUSDW, Some(X86Opcode::PACKUSDW)),
(X86Intrinsic::Sse41_PCmpEQQ, Some(X86Opcode::PCMPEQQ)),
(X86Intrinsic::Sse41_PInsrB, Some(X86Opcode::PINSRB)),
(X86Intrinsic::Sse41_PInsrW, Some(X86Opcode::PINSRW)),
(X86Intrinsic::Sse41_PInsrD, Some(X86Opcode::PINSRD)),
(X86Intrinsic::Sse41_PInsrQ, Some(X86Opcode::PINSRQ)),
(X86Intrinsic::Sse41_PExtrB, Some(X86Opcode::PEXTRB)),
(X86Intrinsic::Sse41_PExtrW, Some(X86Opcode::PEXTRW)),
(X86Intrinsic::Sse41_PExtrD, Some(X86Opcode::PEXTRD)),
(X86Intrinsic::Sse41_PExtrQ, Some(X86Opcode::PEXTRQ)),
(X86Intrinsic::Sse42_Crc32_8, Some(X86Opcode::CRC32)),
(X86Intrinsic::Sse42_Crc32_16, Some(X86Opcode::CRC32)),
(X86Intrinsic::Sse42_Crc32_32, Some(X86Opcode::CRC32)),
(X86Intrinsic::Sse42_Crc32_64, Some(X86Opcode::CRC32)),
(X86Intrinsic::Aes_AesEnc, Some(X86Opcode::AESENC)),
(X86Intrinsic::Aes_AesEncLast, Some(X86Opcode::AESENCLAST)),
(X86Intrinsic::Aes_AesDec, Some(X86Opcode::AESDEC)),
(X86Intrinsic::Aes_AesDecLast, Some(X86Opcode::AESDECLAST)),
(X86Intrinsic::Aes_AesIMC, Some(X86Opcode::AESIMC)),
(
X86Intrinsic::Aes_AesKeyGenAssist,
Some(X86Opcode::AESKEYGENASSIST),
),
(X86Intrinsic::Aes_PCLmulQDQ, Some(X86Opcode::PCLMULQDQ)),
(X86Intrinsic::Sha_Sha1Rnds4, Some(X86Opcode::SHA1RNDS4)),
(X86Intrinsic::Sha_Sha1Nexte, Some(X86Opcode::SHA1NEXTE)),
(X86Intrinsic::Sha_Sha1Msg1, Some(X86Opcode::SHA1MSG1)),
(X86Intrinsic::Sha_Sha1Msg2, Some(X86Opcode::SHA1MSG2)),
(X86Intrinsic::Sha_Sha256Rnds2, Some(X86Opcode::SHA256RNDS2)),
(X86Intrinsic::Sha_Sha256Msg1, Some(X86Opcode::SHA256MSG1)),
(X86Intrinsic::Sha_Sha256Msg2, Some(X86Opcode::SHA256MSG2)),
(X86Intrinsic::RdRand16, Some(X86Opcode::RDRAND16)),
(X86Intrinsic::RdRand32, Some(X86Opcode::RDRAND32)),
(X86Intrinsic::RdRand64, Some(X86Opcode::RDRAND64)),
(X86Intrinsic::RdSeed16, Some(X86Opcode::RDSEED16)),
(X86Intrinsic::RdSeed32, Some(X86Opcode::RDSEED32)),
(X86Intrinsic::RdSeed64, Some(X86Opcode::RDSEED64)),
(X86Intrinsic::Avx_AddPS256, Some(X86Opcode::VADDPS)),
(X86Intrinsic::Avx_AddPD256, Some(X86Opcode::VADDPD)),
(X86Intrinsic::Avx_SubPS256, Some(X86Opcode::VSUBPS)),
(X86Intrinsic::Avx_SubPD256, Some(X86Opcode::VSUBPD)),
(X86Intrinsic::Avx_MulPS256, Some(X86Opcode::VMULPS)),
(X86Intrinsic::Avx_MulPD256, Some(X86Opcode::VMULPD)),
(X86Intrinsic::Avx_DivPS256, Some(X86Opcode::VDIVPS)),
(X86Intrinsic::Avx_DivPD256, Some(X86Opcode::VDIVPD)),
(X86Intrinsic::Avx_AddSS, Some(X86Opcode::VADDSS)),
(X86Intrinsic::Avx_AddSD, Some(X86Opcode::VADDSD)),
(X86Intrinsic::Avx_AndPS256, Some(X86Opcode::VANDPS)),
(X86Intrinsic::Avx_AndnPS256, Some(X86Opcode::VANDNPS)),
(X86Intrinsic::Avx_OrPS256, Some(X86Opcode::VORPS)),
(X86Intrinsic::Avx_XorPS256, Some(X86Opcode::VXORPS)),
(X86Intrinsic::Avx_BroadcastSS, Some(X86Opcode::VBROADCASTSS)),
(X86Intrinsic::Avx_BroadcastSD, Some(X86Opcode::VBROADCASTSD)),
(X86Intrinsic::Avx_Perm2F128, Some(X86Opcode::VPERM2F128)),
(X86Intrinsic::Avx_ZeroAll, Some(X86Opcode::VZEROALL)),
(X86Intrinsic::Avx_ZeroUpper, Some(X86Opcode::VZEROUPPER)),
(X86Intrinsic::Avx2_GatherDPS, Some(X86Opcode::VPGATHERDD)),
(X86Intrinsic::Avx2_GatherDPD, Some(X86Opcode::VPGATHERDQ)),
(X86Intrinsic::Avx2_GatherDD, Some(X86Opcode::VPGATHERDD)),
(X86Intrinsic::Fma_Fmadd132PS, Some(X86Opcode::VFMADD132PS)),
(X86Intrinsic::Fma_Fmadd213PS, Some(X86Opcode::VFMADD213PS)),
(X86Intrinsic::Fma_Fmadd231PS, Some(X86Opcode::VFMADD231PS)),
(X86Intrinsic::Fma_Fmadd132PD, Some(X86Opcode::VFMADD132PD)),
(X86Intrinsic::Fma_Fmadd213PD, Some(X86Opcode::VFMADD213PD)),
(X86Intrinsic::Fma_Fmadd231PD, Some(X86Opcode::VFMADD231PD)),
(X86Intrinsic::Bmi_Andn32, Some(X86Opcode::ANDN)),
(X86Intrinsic::Bmi_Andn64, Some(X86Opcode::ANDN)),
(X86Intrinsic::Bmi_Bextr32, Some(X86Opcode::BEXTR)),
(X86Intrinsic::Bmi_Bextr64, Some(X86Opcode::BEXTR)),
(X86Intrinsic::Bmi_Blsi32, Some(X86Opcode::BLSI)),
(X86Intrinsic::Bmi_Blsmsk32, Some(X86Opcode::BLSMSK)),
(X86Intrinsic::Bmi_Blsr32, Some(X86Opcode::BLSR)),
(X86Intrinsic::Bmi_Tzcnt16, Some(X86Opcode::TZCNT)),
(X86Intrinsic::Bmi_Tzcnt32, Some(X86Opcode::TZCNT)),
(X86Intrinsic::Bmi_Tzcnt64, Some(X86Opcode::TZCNT)),
(X86Intrinsic::Bmi2_Bzhi32, Some(X86Opcode::BZHI)),
(X86Intrinsic::Bmi2_Mulx32, Some(X86Opcode::MULX)),
(X86Intrinsic::Bmi2_Pdep32, Some(X86Opcode::PDEP)),
(X86Intrinsic::Bmi2_Pext32, Some(X86Opcode::PEXT)),
(X86Intrinsic::Bmi2_Rorx32, Some(X86Opcode::RORX)),
(X86Intrinsic::Bmi2_Sarx32, Some(X86Opcode::SARX)),
(X86Intrinsic::Bmi2_Shlx32, Some(X86Opcode::SHLX)),
(X86Intrinsic::Bmi2_Shrx32, Some(X86Opcode::SHRX)),
(X86Intrinsic::Misc_Clflushopt, Some(X86Opcode::CLFLUSHOPT)),
(X86Intrinsic::Misc_Clwb, Some(X86Opcode::CLWB)),
(X86Intrinsic::Misc_Monitorx, Some(X86Opcode::MONITORX_AMD)),
(X86Intrinsic::Misc_MWaitx, Some(X86Opcode::MWAITX_AMD)),
(X86Intrinsic::Misc_Clzero, Some(X86Opcode::CLZERO)),
(X86Intrinsic::Misc_RdTSC, Some(X86Opcode::RDTSC)),
(X86Intrinsic::Misc_RdTSCP, Some(X86Opcode::RDTSCP)),
(X86Intrinsic::Misc_Lzcnt32, Some(X86Opcode::LZCNT32)),
(X86Intrinsic::Misc_Popcnt32, Some(X86Opcode::POPCNT32)),
(X86Intrinsic::Misc_PrefetchW, Some(X86Opcode::PREFETCHW)),
(X86Intrinsic::Avx512_AddPS512, Some(X86Opcode::VADDPS_Z)),
(X86Intrinsic::Avx512_AddPD512, Some(X86Opcode::VADDPD_Z)),
(X86Intrinsic::Avx512_MulPS512, Some(X86Opcode::VMULPS_Z)),
(X86Intrinsic::Avx512_MulPD512, Some(X86Opcode::VMULPD_Z)),
(X86Intrinsic::Avx512_DivPS512, Some(X86Opcode::VDIVPS_Z)),
(X86Intrinsic::Avx512_DivPD512, Some(X86Opcode::VDIVPD_Z)),
(X86Intrinsic::Avx512_PAddD512, Some(X86Opcode::VPADDD_Z)),
(X86Intrinsic::Avx512_PMulLD512, Some(X86Opcode::VPMULLD_Z)),
(X86Intrinsic::Avx512_PAddB512, Some(X86Opcode::VPADDB_Z)),
(X86Intrinsic::Avx512_PAddW512, Some(X86Opcode::VPADDW_Z)),
(X86Intrinsic::Avx512_VPDPBUSD, Some(X86Opcode::VPDPBUSD)),
(X86Intrinsic::Avx512_VPDPWSSD, Some(X86Opcode::VPDPWSSD)),
(
X86Intrinsic::Avx512_VPMadd52LUQ,
Some(X86Opcode::VPMADD52LUQ),
),
(
X86Intrinsic::Avx512_VPMadd52HUQ,
Some(X86Opcode::VPMADD52HUQ),
),
(
X86Intrinsic::Avx512_VGF2P8AffineQB,
Some(X86Opcode::VGF2P8AFFINEQB),
),
(
X86Intrinsic::Avx512_VGF2P8AffineInvQB,
Some(X86Opcode::VGF2P8AFFINEINVQB),
),
(X86Intrinsic::Avx512_VGF2P8MulB, Some(X86Opcode::VGF2P8MULB)),
(X86Intrinsic::Avx512_VAesEnc, Some(X86Opcode::VAESENC)),
(
X86Intrinsic::Avx512_VAesEncLast,
Some(X86Opcode::VAESENCLAST),
),
(X86Intrinsic::Avx512_VAesDec, Some(X86Opcode::VAESDEC)),
(
X86Intrinsic::Avx512_VAesDecLast,
Some(X86Opcode::VAESDECLAST),
),
(X86Intrinsic::Avx512_VPCLmulQDQ, Some(X86Opcode::VPCLMULQDQ)),
(
X86Intrinsic::Avx512_VP2IntersectD,
Some(X86Opcode::VP2INTERSECTD),
),
(
X86Intrinsic::Avx512_VP2IntersectQ,
Some(X86Opcode::VP2INTERSECTQ),
),
(X86Intrinsic::Avx512_DPBf16PS, Some(X86Opcode::VDPBF16PS_Z)),
(
X86Intrinsic::Avx512_CvtNe2Ps2Bf16,
Some(X86Opcode::VCVTNE2PS2BF16_Z),
),
(X86Intrinsic::Amx_TileLoadD, Some(X86Opcode::TILELOADD_Z)),
(X86Intrinsic::Amx_TileStoreD, Some(X86Opcode::TILESTORED_Z)),
(X86Intrinsic::Amx_TileConfig, Some(X86Opcode::TILECONFIG)),
(X86Intrinsic::Amx_TileRelease, Some(X86Opcode::TILERELEASE)),
(X86Intrinsic::Amx_TileZero, Some(X86Opcode::TILEZERO_Z)),
(X86Intrinsic::Amx_TDPBSSD, Some(X86Opcode::TDPBSSD_Z)),
(X86Intrinsic::Amx_TDPBF16PS, Some(X86Opcode::TDPBF16PS_Z)),
];
pub fn lookup_opcode_from_table(intr: X86Intrinsic) -> Option<X86Opcode> {
INTRINSIC_OPCODE_TABLE
.iter()
.find(|(i, _)| *i == intr)
.and_then(|(_, op)| *op)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_table_has_entries() {
let table = X86IntrinsicTable::new();
assert!(
table.len() > 400,
"expected >400 intrinsics, got {}",
table.len()
);
assert!(!table.is_empty());
}
#[test]
fn test_lookup_sse_add_ps() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.sse.add.ps")
.expect("SSE add.ps not found");
assert_eq!(info.intrinsic, X86Intrinsic::Sse_AddPS);
assert_eq!(info.group, X86IntrinsicGroup::SSE);
assert_eq!(info.num_operands, 2);
assert!(info.is_commutative);
}
#[test]
fn test_lookup_sse_sqrt_ps() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.sse.sqrt.ps")
.expect("SSE sqrt.ps not found");
assert_eq!(info.intrinsic, X86Intrinsic::Sse_SqrtPS);
assert_eq!(info.num_operands, 1);
}
#[test]
fn test_lookup_sse2_add_pd() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.sse2.add.pd")
.expect("SSE2 add.pd not found");
assert_eq!(info.intrinsic, X86Intrinsic::Sse2_AddPD);
assert_eq!(info.group, X86IntrinsicGroup::SSE2);
}
#[test]
fn test_lookup_avx_add_ps_256() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.avx.add.ps.256")
.expect("AVX add.ps.256 not found");
assert_eq!(info.intrinsic, X86Intrinsic::Avx_AddPS256);
assert_eq!(info.group, X86IntrinsicGroup::AVX);
}
#[test]
fn test_lookup_aes_enc() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.aesni.aesenc")
.expect("AES enc not found");
assert_eq!(info.intrinsic, X86Intrinsic::Aes_AesEnc);
assert_eq!(info.group, X86IntrinsicGroup::AES);
}
#[test]
fn test_lookup_sha1_rnds4() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.sha1rnds4")
.expect("SHA1RNDS4 not found");
assert_eq!(info.intrinsic, X86Intrinsic::Sha_Sha1Rnds4);
assert_eq!(info.group, X86IntrinsicGroup::SHA);
}
#[test]
fn test_lookup_fma() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.fma.fmadd.132.ps")
.expect("FMA fmadd132ps not found");
assert_eq!(info.intrinsic, X86Intrinsic::Fma_Fmadd132PS);
assert_eq!(info.group, X86IntrinsicGroup::FMA);
}
#[test]
fn test_lookup_avx512_add_ps_512() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.avx512.add.ps.512")
.expect("AVX512 add.ps.512 not found");
assert_eq!(info.intrinsic, X86Intrinsic::Avx512_AddPS512);
assert_eq!(info.group, X86IntrinsicGroup::AVX512F);
assert!(info.has_mask_variant);
assert!(info.has_rounding_variant);
}
#[test]
fn test_lookup_bmi_andn() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.bmi.andn.32")
.expect("BMI andn.32 not found");
assert_eq!(info.intrinsic, X86Intrinsic::Bmi_Andn32);
assert_eq!(info.group, X86IntrinsicGroup::BMI);
}
#[test]
fn test_lookup_bmi2_bzhi() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.bmi2.bzhi.32")
.expect("BMI2 bzhi.32 not found");
assert_eq!(info.intrinsic, X86Intrinsic::Bmi2_Bzhi32);
assert_eq!(info.group, X86IntrinsicGroup::BMI2);
}
#[test]
fn test_lookup_rdrand() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.rdrand.32")
.expect("RDRAND not found");
assert_eq!(info.group, X86IntrinsicGroup::RDRAND);
}
#[test]
fn test_lookup_rdseed() {
let table = X86IntrinsicTable::new();
let info = table
.lookup("llvm.x86.rdseed.32")
.expect("RDSEED not found");
assert_eq!(info.group, X86IntrinsicGroup::RDSEED);
}
#[test]
fn test_group_sse_count() {
let table = X86IntrinsicTable::new();
let count = table.count_in_group(X86IntrinsicGroup::SSE);
assert!(
count >= 30,
"SSE should have >=30 intrinsics, got {}",
count
);
}
#[test]
fn test_group_sse2_count() {
let table = X86IntrinsicTable::new();
let count = table.count_in_group(X86IntrinsicGroup::SSE2);
assert!(
count >= 40,
"SSE2 should have >=40 intrinsics, got {}",
count
);
}
#[test]
fn test_group_avx2_count() {
let table = X86IntrinsicTable::new();
let count = table.count_in_group(X86IntrinsicGroup::AVX2);
assert!(
count >= 10,
"AVX2 should have >=10 intrinsics, got {}",
count
);
}
#[test]
fn test_group_feature_flags() {
assert_eq!(X86IntrinsicGroup::SSE.feature_flag(), "+sse");
assert_eq!(X86IntrinsicGroup::SSE2.feature_flag(), "+sse2");
assert_eq!(X86IntrinsicGroup::AVX512F.feature_flag(), "+avx512f");
assert_eq!(X86IntrinsicGroup::FMA.feature_flag(), "+fma");
}
#[test]
fn test_lookup_by_enum() {
let table = X86IntrinsicTable::new();
let info = table
.lookup_by_enum(X86Intrinsic::Sse2_CvtPD2PS)
.expect("cvtpd2ps not found");
assert_eq!(info.llvm_name, "llvm.x86.sse2.cvtpd2ps");
}
#[test]
fn test_all_intrinsics_covered() {
let table = X86IntrinsicTable::new();
for idx in 0..X86Intrinsic::COUNT {
let intr: X86Intrinsic = unsafe { std::mem::transmute(idx as u16) };
assert!(
table.lookup_by_enum(intr).is_some(),
"intrinsic index {} ({:?}) missing from table",
idx,
intr
);
}
}
#[test]
fn test_intrinsic_count_consistent() {
let last_idx = X86Intrinsic::Misc_Popcnt64.index();
assert_eq!(X86Intrinsic::COUNT, last_idx + 1);
}
#[test]
fn test_emitter_new() {
let emitter = X86IntrinsicEmitter::new();
assert!(emitter.table().len() > 0);
}
#[test]
fn test_emit_add_ps() {
let emitter = X86IntrinsicEmitter::new();
let call = emitter.emit_call(X86Intrinsic::Sse_AddPS, &["%a".into(), "%b".into()]);
assert!(call.contains("llvm.x86.sse.add.ps"));
assert!(call.contains("%a"));
assert!(call.contains("%b"));
}
#[test]
fn test_verifier_operand_count_valid() {
let verifier = X86IntrinsicVerifier::default();
assert_eq!(
verifier.verify_operand_count(X86Intrinsic::Sse_AddPS, 2),
Verdict::Valid
);
}
#[test]
fn test_verifier_operand_count_invalid() {
let verifier = X86IntrinsicVerifier::default();
let result = verifier.verify_operand_count(X86Intrinsic::Sse_AddPS, 3);
assert!(matches!(result, Verdict::Invalid { .. }));
}
#[test]
fn test_verifier_feature_missing() {
let verifier = X86IntrinsicVerifier::new(vec![], true);
let result = verifier.verify_feature(X86Intrinsic::Avx512_AddPS512);
assert!(matches!(result, Verdict::Invalid { .. }));
}
#[test]
fn test_verifier_feature_present() {
let verifier = X86IntrinsicVerifier::new(vec!["+avx512f".into()], true);
assert_eq!(
verifier.verify_feature(X86Intrinsic::Avx512_AddPS512),
Verdict::Valid
);
}
#[test]
fn test_verifier_full_valid() {
let verifier = X86IntrinsicVerifier::new(vec!["+sse".into()], true);
assert_eq!(verifier.verify(X86Intrinsic::Sse_AddPS, 2), Verdict::Valid);
}
#[test]
fn test_lowering_sse_add_ps() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Sse_AddPS),
Some(X86Opcode::ADDPS)
);
}
#[test]
fn test_lowering_aes_enc() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Aes_AesEnc),
Some(X86Opcode::AESENC)
);
}
#[test]
fn test_lowering_sha256_rnds2() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Sha_Sha256Rnds2),
Some(X86Opcode::SHA256RNDS2)
);
}
#[test]
fn test_lowering_avx_add_ps_256() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Avx_AddPS256),
Some(X86Opcode::VADDPS)
);
}
#[test]
fn test_lowering_fma_fmadd132_ps() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Fma_Fmadd132PS),
Some(X86Opcode::VFMADD132PS)
);
}
#[test]
fn test_lowering_bmi_andn() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Bmi_Andn32),
Some(X86Opcode::ANDN)
);
}
#[test]
fn test_lowering_bmi2_bzhi() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Bmi2_Bzhi32),
Some(X86Opcode::BZHI)
);
}
#[test]
fn test_lowering_rdrand() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::RdRand32),
Some(X86Opcode::RDRAND32)
);
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::RdSeed32),
Some(X86Opcode::RDSEED32)
);
}
#[test]
fn test_lowering_avx512f_add_ps_512() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Avx512_AddPS512),
Some(X86Opcode::VADDPS_Z)
);
}
#[test]
fn test_lowering_avx512_vnni() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Avx512_VPDPBUSD),
Some(X86Opcode::VPDPBUSD)
);
}
#[test]
fn test_lowering_avx512_gfni() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Avx512_VGF2P8AffineQB),
Some(X86Opcode::VGF2P8AFFINEQB)
);
}
#[test]
fn test_lowering_avx512_vaes() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Avx512_VAesEnc),
Some(X86Opcode::VAESENC)
);
}
#[test]
fn test_lowering_amx() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Amx_TileLoadD),
Some(X86Opcode::TILELOADD_Z)
);
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Amx_TileConfig),
Some(X86Opcode::TILECONFIG)
);
}
#[test]
fn test_lowering_popcnt_lzcnt() {
let lowering = X86IntrinsicLowering::new();
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Misc_Popcnt32),
Some(X86Opcode::POPCNT32)
);
assert_eq!(
lowering.lower_to_opcode(X86Intrinsic::Misc_Lzcnt32),
Some(X86Opcode::LZCNT32)
);
}
#[test]
fn test_can_expand_inline() {
let lowering = X86IntrinsicLowering::new();
assert!(lowering.can_expand_inline(X86Intrinsic::Avx_ZeroAll));
assert!(!lowering.can_expand_inline(X86Intrinsic::Sse_AddPS));
}
#[test]
fn test_ret_type_desc_to_type_str() {
assert_eq!(RetTypeDesc::V4F32.to_type_str(), "<4 x f32>");
assert_eq!(RetTypeDesc::V2F64.to_type_str(), "<2 x f64>");
assert_eq!(RetTypeDesc::I32.to_type_str(), "i32");
assert_eq!(RetTypeDesc::Void.to_type_str(), "void");
assert_eq!(RetTypeDesc::V16F32.to_type_str(), "<16 x f32>");
}
#[test]
fn test_align_info_constants() {
assert_eq!(AlignInfo::ALIGN_16.prefer_align_bytes, 16);
assert_eq!(AlignInfo::ALIGN_32.min_align_bytes, 1);
}
#[test]
fn test_intrinsic_index_roundtrip() {
for idx in 0..10 {
let intr: X86Intrinsic = unsafe { std::mem::transmute(idx as u16) };
assert_eq!(intr.index(), idx);
}
}
#[test]
fn test_group_as_str() {
assert_eq!(X86IntrinsicGroup::SSE.as_str(), "sse");
assert_eq!(X86IntrinsicGroup::AVX512F.as_str(), "avx512f");
assert_eq!(X86IntrinsicGroup::FMA.as_str(), "fma");
}
#[test]
fn test_lowering_sse2_full() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_AddPD),
Some(X86Opcode::ADDPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_SubPD),
Some(X86Opcode::SUBPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_MulPD),
Some(X86Opcode::MULPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_DivPD),
Some(X86Opcode::DIVPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_SqrtPD),
Some(X86Opcode::SQRTPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_CvtPD2PS),
Some(X86Opcode::CVTDQ2PS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_CvtPS2DQ),
Some(X86Opcode::CVTPS2DQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_MovDQA),
Some(X86Opcode::MOVDQA)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_PAnd),
Some(X86Opcode::ANDPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_PXor),
Some(X86Opcode::XORPS)
);
}
#[test]
fn test_lowering_sse3_full() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse3_HAddPS),
Some(X86Opcode::HADDPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse3_HSubPS),
Some(X86Opcode::HSUBPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse3_AddSubPS),
Some(X86Opcode::ADDSUBPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse3_MovDDup),
Some(X86Opcode::MOVDDUP)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse3_MovSHDup),
Some(X86Opcode::MOVSHDUP)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse3_MovSLDup),
Some(X86Opcode::MOVSLDUP)
);
}
#[test]
fn test_lowering_ssse3_full() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PHAddW),
Some(X86Opcode::PHADDW)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PHAddD),
Some(X86Opcode::PHADDD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PSignB),
Some(X86Opcode::PSIGNB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PSignW),
Some(X86Opcode::PSIGNW)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PSignD),
Some(X86Opcode::PSIGND)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PAbsB),
Some(X86Opcode::PABSB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PAbsW),
Some(X86Opcode::PABSW)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Ssse3_PAbsD),
Some(X86Opcode::PABSD)
);
}
#[test]
fn test_lowering_sse41_full() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PMulLD),
Some(X86Opcode::PMULLD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PMinSB),
Some(X86Opcode::PMINSB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PMaxSB),
Some(X86Opcode::PMAXSB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PMinSD),
Some(X86Opcode::PMINSD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PMaxSD),
Some(X86Opcode::PMAXSD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_BlendPS),
Some(X86Opcode::BLENDPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_BlendPD),
Some(X86Opcode::BLENDPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_RoundPS),
Some(X86Opcode::ROUNDPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_RoundPD),
Some(X86Opcode::ROUNDPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PCmpEQQ),
Some(X86Opcode::PCMPEQQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PInsrB),
Some(X86Opcode::PINSRB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PExtrB),
Some(X86Opcode::PEXTRB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PInsrD),
Some(X86Opcode::PINSRD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_PExtrD),
Some(X86Opcode::PEXTRD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_ExtractPS),
Some(X86Opcode::EXTRACTPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse41_InsertPS),
Some(X86Opcode::INSERTPS)
);
}
#[test]
fn test_lowering_avx_misc() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_MulPS256),
Some(X86Opcode::VMULPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_DivPS256),
Some(X86Opcode::VDIVPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_AndPS256),
Some(X86Opcode::VANDPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_OrPS256),
Some(X86Opcode::VORPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_XorPS256),
Some(X86Opcode::VXORPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_ZeroAll),
Some(X86Opcode::VZEROALL)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_ZeroUpper),
Some(X86Opcode::VZEROUPPER)
);
}
#[test]
fn test_lowering_avx512f_misc() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_MulPS512),
Some(X86Opcode::VMULPS_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_DivPS512),
Some(X86Opcode::VDIVPS_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_AddPD512),
Some(X86Opcode::VADDPD_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_MulPD512),
Some(X86Opcode::VMULPD_Z)
);
}
#[test]
fn test_lowering_avx512_dq_bw() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_PAddD512),
Some(X86Opcode::VPADDD_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_PMulLD512),
Some(X86Opcode::VPMULLD_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_PAddB512),
Some(X86Opcode::VPADDB_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_PAddW512),
Some(X86Opcode::VPADDW_Z)
);
}
#[test]
fn test_lowering_misc_extended() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Clflushopt),
Some(X86Opcode::CLFLUSHOPT)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Clwb),
Some(X86Opcode::CLWB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Monitorx),
Some(X86Opcode::MONITORX_AMD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_MWaitx),
Some(X86Opcode::MWAITX_AMD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Clzero),
Some(X86Opcode::CLZERO)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_RdTSC),
Some(X86Opcode::RDTSC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_PrefetchW),
Some(X86Opcode::PREFETCHW)
);
}
#[test]
fn test_lowering_gfni_vaes_amx() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VGF2P8AffineQB),
Some(X86Opcode::VGF2P8AFFINEQB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VGF2P8AffineInvQB),
Some(X86Opcode::VGF2P8AFFINEINVQB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VGF2P8MulB),
Some(X86Opcode::VGF2P8MULB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VAesDec),
Some(X86Opcode::VAESDEC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VPCLmulQDQ),
Some(X86Opcode::VPCLMULQDQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VP2IntersectD),
Some(X86Opcode::VP2INTERSECTD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VP2IntersectQ),
Some(X86Opcode::VP2INTERSECTQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_DPBf16PS),
Some(X86Opcode::VDPBF16PS_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_CvtNe2Ps2Bf16),
Some(X86Opcode::VCVTNE2PS2BF16_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TileStoreD),
Some(X86Opcode::TILESTORED_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TileRelease),
Some(X86Opcode::TILERELEASE)
);
}
#[test]
fn test_verifier_all_features() {
let v = X86IntrinsicVerifier::new(vec!["+sse".into(), "+sse2".into(), "+avx".into()], true);
assert_eq!(v.verify(X86Intrinsic::Sse_AddPS, 2), Verdict::Valid);
assert_eq!(v.verify(X86Intrinsic::Sse2_AddPD, 2), Verdict::Valid);
assert_eq!(v.verify(X86Intrinsic::Avx_AddPS256, 2), Verdict::Valid);
}
#[test]
fn test_emitter_fma_call() {
let emitter = X86IntrinsicEmitter::new();
let call = emitter.emit_call(
X86Intrinsic::Fma_Fmadd213PS,
&["%a".into(), "%b".into(), "%c".into()],
);
assert!(call.contains("llvm.x86.fma.fmadd.213.ps"));
assert!(call.contains("%a"));
assert!(call.contains("%b"));
assert!(call.contains("%c"));
}
#[test]
fn test_emitter_aes_call() {
let emitter = X86IntrinsicEmitter::new();
let call = emitter.emit_call(X86Intrinsic::Aes_AesEnc, &["%state".into(), "%key".into()]);
assert!(call.contains("llvm.x86.aesni.aesenc"));
}
#[test]
fn test_table_group_by() {
let table = X86IntrinsicTable::new();
let sse3_group = table.by_group(X86IntrinsicGroup::SSE3);
assert!(sse3_group.len() > 0, "SSE3 group should not be empty");
let aes_group = table.by_group(X86IntrinsicGroup::AES);
assert!(aes_group.len() > 0, "AES group should not be empty");
let sha_group = table.by_group(X86IntrinsicGroup::SHA);
assert!(sha_group.len() > 0, "SHA group should not be empty");
let avx512f_group = table.by_group(X86IntrinsicGroup::AVX512F);
assert!(
avx512f_group.len() > 0,
"AVX-512F group should not be empty"
);
let amx_group = table.by_group(X86IntrinsicGroup::AMX);
assert!(amx_group.len() > 0, "AMX group should not be empty");
}
#[test]
fn test_table_counts_coherent() {
let table = X86IntrinsicTable::new();
let total_by_group: usize = [
X86IntrinsicGroup::SSE,
X86IntrinsicGroup::SSE2,
X86IntrinsicGroup::SSE3,
X86IntrinsicGroup::SSSE3,
X86IntrinsicGroup::SSE41,
X86IntrinsicGroup::SSE42,
X86IntrinsicGroup::AVX,
X86IntrinsicGroup::AVX2,
X86IntrinsicGroup::FMA,
X86IntrinsicGroup::BMI,
X86IntrinsicGroup::BMI2,
X86IntrinsicGroup::ADX,
X86IntrinsicGroup::AES,
X86IntrinsicGroup::SHA,
X86IntrinsicGroup::RDRAND,
X86IntrinsicGroup::RDSEED,
X86IntrinsicGroup::CLFLUSHOPT,
X86IntrinsicGroup::LZCNT,
X86IntrinsicGroup::POPCNT,
X86IntrinsicGroup::XSAVE,
X86IntrinsicGroup::MOVDIR,
X86IntrinsicGroup::AVX512F,
X86IntrinsicGroup::AVX512CD,
X86IntrinsicGroup::AVX512ER,
X86IntrinsicGroup::AVX512PF,
X86IntrinsicGroup::AVX512BW,
X86IntrinsicGroup::AVX512DQ,
X86IntrinsicGroup::AVX512VL,
X86IntrinsicGroup::AVX512IFMA,
X86IntrinsicGroup::AVX512VBMI,
X86IntrinsicGroup::AVX512VBMI2,
X86IntrinsicGroup::AVX512VNNI,
X86IntrinsicGroup::AVX512BITALG,
X86IntrinsicGroup::AVX512VPOPCNTDQ,
X86IntrinsicGroup::AVX512BF16,
X86IntrinsicGroup::AVX512FP16,
X86IntrinsicGroup::AVX512VAES,
X86IntrinsicGroup::AVX512GFNI,
X86IntrinsicGroup::AVX512VP2INTERSECT,
X86IntrinsicGroup::AMX,
X86IntrinsicGroup::Misc,
]
.iter()
.map(|&g| table.count_in_group(g))
.sum();
assert_eq!(
total_by_group,
table.len(),
"Sum of group counts ({}) should equal total table length ({})",
total_by_group,
table.len()
);
}
#[test]
fn test_feature_flags_comprehensive() {
for group in &[
X86IntrinsicGroup::SSE,
X86IntrinsicGroup::SSE2,
X86IntrinsicGroup::SSE3,
X86IntrinsicGroup::SSSE3,
X86IntrinsicGroup::SSE41,
X86IntrinsicGroup::SSE42,
X86IntrinsicGroup::AVX,
X86IntrinsicGroup::AVX2,
X86IntrinsicGroup::FMA,
X86IntrinsicGroup::BMI,
X86IntrinsicGroup::BMI2,
X86IntrinsicGroup::ADX,
X86IntrinsicGroup::AES,
X86IntrinsicGroup::SHA,
X86IntrinsicGroup::RDRAND,
X86IntrinsicGroup::RDSEED,
X86IntrinsicGroup::CLFLUSHOPT,
X86IntrinsicGroup::LZCNT,
X86IntrinsicGroup::POPCNT,
X86IntrinsicGroup::XSAVE,
X86IntrinsicGroup::MOVDIR,
X86IntrinsicGroup::AVX512F,
X86IntrinsicGroup::AVX512CD,
X86IntrinsicGroup::AVX512ER,
X86IntrinsicGroup::AVX512BW,
X86IntrinsicGroup::AVX512DQ,
X86IntrinsicGroup::AVX512VNNI,
X86IntrinsicGroup::AVX512BITALG,
X86IntrinsicGroup::AVX512BF16,
X86IntrinsicGroup::AVX512FP16,
X86IntrinsicGroup::AVX512VAES,
X86IntrinsicGroup::AVX512GFNI,
X86IntrinsicGroup::AVX512VP2INTERSECT,
X86IntrinsicGroup::AMX,
] {
let flag = group.feature_flag();
assert!(
!flag.is_empty() || matches!(group, X86IntrinsicGroup::Misc),
"Group {:?} has empty feature flag",
group
);
}
}
#[test]
fn test_memory_intrinsics_have_side_effects() {
let table = X86IntrinsicTable::new();
let mem_intrinsics = [
X86Intrinsic::Sse_MovntPS,
X86Intrinsic::Sse_Prefetch,
X86Intrinsic::Misc_Clflushopt,
X86Intrinsic::Misc_Monitorx,
X86Intrinsic::Misc_MWaitx,
X86Intrinsic::Misc_Clzero,
X86Intrinsic::Amx_TileLoadD,
X86Intrinsic::Amx_TileStoreD,
X86Intrinsic::Amx_TileConfig,
];
for &intr in &mem_intrinsics {
if let Some(info) = table.lookup_by_enum(intr) {
assert_ne!(
info.side_effects,
IntrinsicSideEffect::None,
"Memory intrinsic {:?} should have side effects",
intr
);
}
}
}
#[test]
fn test_avx512_mask_variants() {
let table = X86IntrinsicTable::new();
let avx512f_entries = table.by_group(X86IntrinsicGroup::AVX512F);
let maskable_count = avx512f_entries
.iter()
.filter(|e| e.has_mask_variant)
.count();
assert!(
maskable_count > 0,
"AVX-512F should have mask-variant intrinsics"
);
}
#[test]
fn test_no_duplicate_llvm_names() {
let table = X86IntrinsicTable::new();
let mut names: std::collections::HashSet<&str> = std::collections::HashSet::new();
for info in table.all() {
if info.llvm_name.starts_with("llvm.x86.") {
assert!(
names.insert(info.llvm_name),
"Duplicate LLVM intrinsic name: {}",
info.llvm_name
);
}
}
}
#[test]
fn test_every_intrinsic_has_feature_flag() {
let table = X86IntrinsicTable::new();
for info in table.all() {
let flag = info.min_feature;
if info.group != X86IntrinsicGroup::Misc {
assert!(
!flag.is_empty(),
"Intrinsic {:?} in group {:?} has empty feature flag",
info.intrinsic,
info.group
);
}
}
}
#[test]
fn test_every_intrinsic_has_valid_operand_count() {
let table = X86IntrinsicTable::new();
for info in table.all() {
assert!(
info.num_operands <= 5,
"Intrinsic {:?} has excessive operands: {}",
info.intrinsic,
info.num_operands
);
assert_eq!(
info.num_operands,
info.param_types.len(),
"Intrinsic {:?} operand count mismatch: {} vs param_types len {}",
info.intrinsic,
info.num_operands,
info.param_types.len()
);
}
}
#[test]
fn test_static_opcode_table_coverage() {
let lowering = X86IntrinsicLowering::new();
let table = X86IntrinsicTable::new();
let mut covered = 0usize;
let mut total = 0usize;
for info in table.all() {
total += 1;
if lowering.lower_to_opcode(info.intrinsic).is_some() {
covered += 1;
}
}
let pct = (covered as f64 / total as f64) * 100.0;
assert!(pct > 15.0, "Lowering coverage {:.1}% too low", pct);
}
#[test]
fn test_static_table_matches_lowering() {
let lowering = X86IntrinsicLowering::new();
for &(intr, expected) in INTRINSIC_OPCODE_TABLE {
let actual = lowering.lower_to_opcode(intr);
assert_eq!(
actual, expected,
"Static table mismatch for {:?}: expected {:?}, got {:?}",
intr, expected, actual
);
}
}
#[test]
fn test_lowering_sse_arithmetic() {
let l = X86IntrinsicLowering::new();
let ops: &[(X86Intrinsic, X86Opcode)] = &[
(X86Intrinsic::Sse_AddPS, X86Opcode::ADDPS),
(X86Intrinsic::Sse_SubPS, X86Opcode::SUBPS),
(X86Intrinsic::Sse_MulPS, X86Opcode::MULPS),
(X86Intrinsic::Sse_DivPS, X86Opcode::DIVPS),
(X86Intrinsic::Sse_SqrtPS, X86Opcode::SQRTPS),
(X86Intrinsic::Sse_RcpPS, X86Opcode::RCPPS),
(X86Intrinsic::Sse_RsqrtPS, X86Opcode::RSQRTPS),
];
for &(intr, expected) in ops {
assert_eq!(
l.lower_to_opcode(intr),
Some(expected),
"SSE arithmetic intrinsic {:?}",
intr
);
}
}
#[test]
fn test_lowering_sse_bitwise() {
let l = X86IntrinsicLowering::new();
let ops: &[(X86Intrinsic, X86Opcode)] = &[
(X86Intrinsic::Sse_AndPS, X86Opcode::ANDPS),
(X86Intrinsic::Sse_AndnPS, X86Opcode::ANDNPS),
(X86Intrinsic::Sse_OrPS, X86Opcode::ORPS),
(X86Intrinsic::Sse_XorPS, X86Opcode::XORPS),
(X86Intrinsic::Sse2_AndPD, X86Opcode::ANDPD),
(X86Intrinsic::Sse2_AndnPD, X86Opcode::ANDNPD),
(X86Intrinsic::Sse2_OrPD, X86Opcode::ORPD),
(X86Intrinsic::Sse2_XorPD, X86Opcode::XORPD),
];
for &(intr, expected) in ops {
assert_eq!(
l.lower_to_opcode(intr),
Some(expected),
"SSE bitwise intrinsic {:?}",
intr
);
}
}
#[test]
fn test_lowering_sse_conversions() {
let l = X86IntrinsicLowering::new();
let ops: &[(X86Intrinsic, X86Opcode)] = &[
(X86Intrinsic::Sse_CvtSI2SS, X86Opcode::CVTSI2SS),
(X86Intrinsic::Sse_CvtSS2SI, X86Opcode::CVTSS2SI),
(X86Intrinsic::Sse_CvttSS2SI, X86Opcode::CVTTSS2SI),
(X86Intrinsic::Sse2_CvtSD2SS, X86Opcode::CVTSD2SS),
(X86Intrinsic::Sse2_CvtSS2SD, X86Opcode::CVTSS2SD),
(X86Intrinsic::Sse2_CvtSD2SI, X86Opcode::CVTSD2SI),
(X86Intrinsic::Sse2_CvttSD2SI, X86Opcode::CVTTSD2SI),
(X86Intrinsic::Sse2_CvtSI2SD, X86Opcode::CVTSI2SD),
(X86Intrinsic::Sse2_CvtPS2DQ, X86Opcode::CVTPS2DQ),
(X86Intrinsic::Sse2_CvtTPS2DQ, X86Opcode::CVTTPS2DQ),
];
for &(intr, expected) in ops {
assert_eq!(
l.lower_to_opcode(intr),
Some(expected),
"SSE conversion intrinsic {:?}",
intr
);
}
}
#[test]
fn test_lowering_sse_shuffle_unpack() {
let l = X86IntrinsicLowering::new();
let ops: &[(X86Intrinsic, X86Opcode)] = &[
(X86Intrinsic::Sse_ShufPS, X86Opcode::SHUFPS),
(X86Intrinsic::Sse_UnpcklPS, X86Opcode::UNPCKLPS),
(X86Intrinsic::Sse_UnpckhPS, X86Opcode::UNPCKHPS),
(X86Intrinsic::Sse2_ShufPD, X86Opcode::SHUFPD),
(X86Intrinsic::Sse2_UnpcklPD, X86Opcode::UNPCKLPD),
(X86Intrinsic::Sse2_UnpckhPD, X86Opcode::UNPCKHPD),
(X86Intrinsic::Sse2_PShufD, X86Opcode::PSHUFD),
];
for &(intr, expected) in ops {
assert_eq!(
l.lower_to_opcode(intr),
Some(expected),
"SSE shuffle intrinsic {:?}",
intr
);
}
}
#[test]
fn test_lowering_sse_moves_complete() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse_MovSS),
Some(X86Opcode::MOVSS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse_MovHLPS),
Some(X86Opcode::MOVHLPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse_MovLHPS),
Some(X86Opcode::MOVLHPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_MovDQA),
Some(X86Opcode::MOVDQA)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_MovDQU),
Some(X86Opcode::MOVDQU)
);
}
#[test]
fn test_lowering_sse_fences() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse_Sfence),
Some(X86Opcode::SFENCE)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_LFence),
Some(X86Opcode::LFENCE)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sse2_MFence),
Some(X86Opcode::MFENCE)
);
}
#[test]
fn test_lowering_sse41_complete() {
let l = X86IntrinsicLowering::new();
let ops: &[(X86Intrinsic, X86Opcode)] = &[
(X86Intrinsic::Sse41_PMulLD, X86Opcode::PMULLD),
(X86Intrinsic::Sse41_PMulDQ, X86Opcode::PMULDQ),
(X86Intrinsic::Sse41_PMinSB, X86Opcode::PMINSB),
(X86Intrinsic::Sse41_PMinSD, X86Opcode::PMINSD),
(X86Intrinsic::Sse41_PMinUW, X86Opcode::PMINUW),
(X86Intrinsic::Sse41_PMinUD, X86Opcode::PMINUD),
(X86Intrinsic::Sse41_PMaxSB, X86Opcode::PMAXSB),
(X86Intrinsic::Sse41_PMaxSD, X86Opcode::PMAXSD),
(X86Intrinsic::Sse41_PMaxUW, X86Opcode::PMAXUW),
(X86Intrinsic::Sse41_PMaxUD, X86Opcode::PMAXUD),
(X86Intrinsic::Sse41_BlendPS, X86Opcode::BLENDPS),
(X86Intrinsic::Sse41_BlendPD, X86Opcode::BLENDPD),
(X86Intrinsic::Sse41_BlendvPS, X86Opcode::BLENDVPS),
(X86Intrinsic::Sse41_BlendvPD, X86Opcode::BLENDVPD),
(X86Intrinsic::Sse41_DppS, X86Opcode::DPPS),
(X86Intrinsic::Sse41_DppD, X86Opcode::DPPD),
(X86Intrinsic::Sse41_RoundPS, X86Opcode::ROUNDPS),
(X86Intrinsic::Sse41_RoundPD, X86Opcode::ROUNDPD),
(X86Intrinsic::Sse41_ExtractPS, X86Opcode::EXTRACTPS),
(X86Intrinsic::Sse41_InsertPS, X86Opcode::INSERTPS),
(X86Intrinsic::Sse41_PackUSDW, X86Opcode::PACKUSDW),
(X86Intrinsic::Sse41_PCmpEQQ, X86Opcode::PCMPEQQ),
(X86Intrinsic::Sse41_PInsrB, X86Opcode::PINSRB),
(X86Intrinsic::Sse41_PInsrW, X86Opcode::PINSRW),
(X86Intrinsic::Sse41_PInsrD, X86Opcode::PINSRD),
(X86Intrinsic::Sse41_PInsrQ, X86Opcode::PINSRQ),
(X86Intrinsic::Sse41_PExtrB, X86Opcode::PEXTRB),
(X86Intrinsic::Sse41_PExtrW, X86Opcode::PEXTRW),
(X86Intrinsic::Sse41_PExtrD, X86Opcode::PEXTRD),
(X86Intrinsic::Sse41_PExtrQ, X86Opcode::PEXTRQ),
];
for &(intr, expected) in ops {
assert_eq!(
l.lower_to_opcode(intr),
Some(expected),
"SSE4.1 intrinsic {:?}",
intr
);
}
}
#[test]
fn test_lowering_crypto_full() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Aes_AesEnc),
Some(X86Opcode::AESENC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Aes_AesEncLast),
Some(X86Opcode::AESENCLAST)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Aes_AesDec),
Some(X86Opcode::AESDEC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Aes_AesDecLast),
Some(X86Opcode::AESDECLAST)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Aes_AesIMC),
Some(X86Opcode::AESIMC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Aes_AesKeyGenAssist),
Some(X86Opcode::AESKEYGENASSIST)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Aes_PCLmulQDQ),
Some(X86Opcode::PCLMULQDQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sha_Sha1Rnds4),
Some(X86Opcode::SHA1RNDS4)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sha_Sha1Nexte),
Some(X86Opcode::SHA1NEXTE)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sha_Sha1Msg1),
Some(X86Opcode::SHA1MSG1)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sha_Sha1Msg2),
Some(X86Opcode::SHA1MSG2)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sha_Sha256Rnds2),
Some(X86Opcode::SHA256RNDS2)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sha_Sha256Msg1),
Some(X86Opcode::SHA256MSG1)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Sha_Sha256Msg2),
Some(X86Opcode::SHA256MSG2)
);
}
#[test]
fn test_lowering_avx_256bit_all() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_AddPS256),
Some(X86Opcode::VADDPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_AddPD256),
Some(X86Opcode::VADDPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_SubPS256),
Some(X86Opcode::VSUBPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_MulPS256),
Some(X86Opcode::VMULPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_DivPS256),
Some(X86Opcode::VDIVPS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_MulPD256),
Some(X86Opcode::VMULPD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx_DivPD256),
Some(X86Opcode::VDIVPD)
);
}
#[test]
fn test_lowering_fma_all_mapped() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Fma_Fmadd132PS),
Some(X86Opcode::VFMADD132PS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Fma_Fmadd213PS),
Some(X86Opcode::VFMADD213PS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Fma_Fmadd231PS),
Some(X86Opcode::VFMADD231PS)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Fma_Fmadd132PD),
Some(X86Opcode::VFMADD132PD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Fma_Fmadd213PD),
Some(X86Opcode::VFMADD213PD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Fma_Fmadd231PD),
Some(X86Opcode::VFMADD231PD)
);
}
#[test]
fn test_lowering_bmi_all() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Andn32),
Some(X86Opcode::ANDN)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Bextr32),
Some(X86Opcode::BEXTR)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Blsi32),
Some(X86Opcode::BLSI)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Blsmsk32),
Some(X86Opcode::BLSMSK)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Blsr32),
Some(X86Opcode::BLSR)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Tzcnt16),
Some(X86Opcode::TZCNT)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Tzcnt32),
Some(X86Opcode::TZCNT)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi_Tzcnt64),
Some(X86Opcode::TZCNT)
);
}
#[test]
fn test_lowering_bmi2_all() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Bzhi32),
Some(X86Opcode::BZHI)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Mulx32),
Some(X86Opcode::MULX)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Pdep32),
Some(X86Opcode::PDEP)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Pext32),
Some(X86Opcode::PEXT)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Rorx32),
Some(X86Opcode::RORX)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Sarx32),
Some(X86Opcode::SARX)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Shlx32),
Some(X86Opcode::SHLX)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Bmi2_Shrx32),
Some(X86Opcode::SHRX)
);
}
#[test]
fn test_lowering_avx512_extended() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VPMadd52LUQ),
Some(X86Opcode::VPMADD52LUQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VPMadd52HUQ),
Some(X86Opcode::VPMADD52HUQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VPDPBUSD),
Some(X86Opcode::VPDPBUSD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VPDPWSSD),
Some(X86Opcode::VPDPWSSD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VGF2P8AffineQB),
Some(X86Opcode::VGF2P8AFFINEQB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VGF2P8AffineInvQB),
Some(X86Opcode::VGF2P8AFFINEINVQB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VGF2P8MulB),
Some(X86Opcode::VGF2P8MULB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VAesEnc),
Some(X86Opcode::VAESENC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VAesDec),
Some(X86Opcode::VAESDEC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VPCLmulQDQ),
Some(X86Opcode::VPCLMULQDQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VP2IntersectD),
Some(X86Opcode::VP2INTERSECTD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_VP2IntersectQ),
Some(X86Opcode::VP2INTERSECTQ)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_DPBf16PS),
Some(X86Opcode::VDPBF16PS_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Avx512_CvtNe2Ps2Bf16),
Some(X86Opcode::VCVTNE2PS2BF16_Z)
);
}
#[test]
fn test_lowering_amx_all() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TileLoadD),
Some(X86Opcode::TILELOADD_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TileStoreD),
Some(X86Opcode::TILESTORED_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TileConfig),
Some(X86Opcode::TILECONFIG)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TileRelease),
Some(X86Opcode::TILERELEASE)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TileZero),
Some(X86Opcode::TILEZERO_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TDPBSSD),
Some(X86Opcode::TDPBSSD_Z)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Amx_TDPBF16PS),
Some(X86Opcode::TDPBF16PS_Z)
);
}
#[test]
fn test_lowering_misc_all() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Clflushopt),
Some(X86Opcode::CLFLUSHOPT)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Clwb),
Some(X86Opcode::CLWB)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Monitorx),
Some(X86Opcode::MONITORX_AMD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_MWaitx),
Some(X86Opcode::MWAITX_AMD)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Clzero),
Some(X86Opcode::CLZERO)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_RdTSC),
Some(X86Opcode::RDTSC)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_RdTSCP),
Some(X86Opcode::RDTSCP)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_PrefetchW),
Some(X86Opcode::PREFETCHW)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_PrefetchWt1),
Some(X86Opcode::PREFETCHWT1)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Lzcnt16),
Some(X86Opcode::LZCNT16)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Lzcnt32),
Some(X86Opcode::LZCNT32)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Lzcnt64),
Some(X86Opcode::LZCNT64)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Popcnt16),
Some(X86Opcode::POPCNT16)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Popcnt32),
Some(X86Opcode::POPCNT32)
);
assert_eq!(
l.lower_to_opcode(X86Intrinsic::Misc_Popcnt64),
Some(X86Opcode::POPCNT64)
);
}
#[test]
fn test_verifier_handles_unknown_intrinsic() {
let v = X86IntrinsicVerifier::default();
let result = v.verify_operand_count(X86Intrinsic::Sse_Movnti, 99);
assert!(matches!(result, Verdict::Invalid { .. }));
}
#[test]
fn test_verifier_feature_empty_flag() {
let v = X86IntrinsicVerifier::new(vec![], false);
assert_eq!(v.verify_feature(X86Intrinsic::Misc_RdTSC), Verdict::Valid);
}
#[test]
fn test_table_by_group_all_nonempty() {
let table = X86IntrinsicTable::new();
let required_groups = [
X86IntrinsicGroup::SSE,
X86IntrinsicGroup::SSE2,
X86IntrinsicGroup::SSE3,
X86IntrinsicGroup::SSSE3,
X86IntrinsicGroup::SSE41,
X86IntrinsicGroup::SSE42,
X86IntrinsicGroup::AVX,
X86IntrinsicGroup::AVX2,
X86IntrinsicGroup::FMA,
X86IntrinsicGroup::BMI,
X86IntrinsicGroup::BMI2,
X86IntrinsicGroup::AES,
X86IntrinsicGroup::SHA,
X86IntrinsicGroup::AVX512F,
X86IntrinsicGroup::AVX512DQ,
X86IntrinsicGroup::AVX512BW,
X86IntrinsicGroup::AVX512VNNI,
X86IntrinsicGroup::AVX512IFMA,
X86IntrinsicGroup::AVX512GFNI,
X86IntrinsicGroup::AVX512VAES,
X86IntrinsicGroup::AMX,
];
for &group in &required_groups {
let entries = table.by_group(group);
assert!(!entries.is_empty(), "Group {:?} should have entries", group);
}
}
#[test]
fn test_static_table_no_duplicates() {
let mut seen: std::collections::HashSet<X86Intrinsic> = std::collections::HashSet::new();
for &(intr, _) in INTRINSIC_OPCODE_TABLE {
assert!(
seen.insert(intr),
"Duplicate intrinsic {:?} in static opcode table",
intr
);
}
}
#[test]
fn test_static_table_sorted_by_isa() {
let groups = [
("SSE", X86IntrinsicGroup::SSE),
("SSE2", X86IntrinsicGroup::SSE2),
("SSE3", X86IntrinsicGroup::SSE3),
("SSSE3", X86IntrinsicGroup::SSSE3),
("SSE4.1", X86IntrinsicGroup::SSE41),
("SSE4.2", X86IntrinsicGroup::SSE42),
("AES", X86IntrinsicGroup::AES),
("SHA", X86IntrinsicGroup::SHA),
("AVX", X86IntrinsicGroup::AVX),
("AVX2", X86IntrinsicGroup::AVX2),
("FMA", X86IntrinsicGroup::FMA),
("BMI", X86IntrinsicGroup::BMI),
("BMI2", X86IntrinsicGroup::BMI2),
("AVX-512F", X86IntrinsicGroup::AVX512F),
("AVX-512DQ", X86IntrinsicGroup::AVX512DQ),
("AVX-512BW", X86IntrinsicGroup::AVX512BW),
];
for &(name, group) in &groups {
let count = INTRINSIC_OPCODE_TABLE
.iter()
.filter(|(i, _)| {
let idx = i.index();
idx >= group_boundary_start(group) && idx <= group_boundary_end(group)
})
.count();
if matches!(
group,
X86IntrinsicGroup::SSE
| X86IntrinsicGroup::SSE2
| X86IntrinsicGroup::AVX
| X86IntrinsicGroup::AES
| X86IntrinsicGroup::SHA
) {
assert!(
count > 0,
"Group {} should have entries in static table",
name
);
}
}
}
}
fn group_boundary_start(g: X86IntrinsicGroup) -> usize {
match g {
X86IntrinsicGroup::SSE => 0,
X86IntrinsicGroup::SSE2 => X86Intrinsic::Sse_PshufW.index() + 1,
X86IntrinsicGroup::SSE3 => X86Intrinsic::Sse2_MaskmovDQU.index() + 1,
X86IntrinsicGroup::SSSE3 => X86Intrinsic::Sse3_MWait.index() + 1,
X86IntrinsicGroup::SSE41 => X86Intrinsic::Ssse3_PAlignr.index() + 1,
X86IntrinsicGroup::SSE42 => X86Intrinsic::Sse41_PMovZXWQ.index() + 1,
X86IntrinsicGroup::AES => X86Intrinsic::Sse42_Popcnt.index() + 1,
X86IntrinsicGroup::SHA => X86Intrinsic::Aes_PCLmulQDQ.index() + 1,
X86IntrinsicGroup::RDRAND => X86Intrinsic::Sha_Sha256Msg2.index() + 1,
X86IntrinsicGroup::RDSEED => X86Intrinsic::RdRand64.index() + 1,
X86IntrinsicGroup::AVX => X86Intrinsic::RdSeed64.index() + 1,
X86IntrinsicGroup::AVX2 => X86Intrinsic::Avx_MovntDQ256.index() + 1,
X86IntrinsicGroup::FMA => X86Intrinsic::Avx2_PShufD256.index() + 1,
X86IntrinsicGroup::BMI => X86Intrinsic::Fma_Fmsubadd231PD256.index() + 1,
X86IntrinsicGroup::BMI2 => X86Intrinsic::Bmi_Tzcnt64.index() + 1,
X86IntrinsicGroup::ADX => X86Intrinsic::Bmi2_Shrx64.index() + 1,
X86IntrinsicGroup::CLFLUSHOPT => X86Intrinsic::Adx_Adox64.index() + 1,
X86IntrinsicGroup::AVX512F => X86Intrinsic::Misc_Popcnt64.index() + 1,
_ => 0,
}
}
fn group_boundary_end(g: X86IntrinsicGroup) -> usize {
match g {
X86IntrinsicGroup::SSE => X86Intrinsic::Sse_PshufW.index(),
X86IntrinsicGroup::SSE2 => X86Intrinsic::Sse2_MaskmovDQU.index(),
X86IntrinsicGroup::SSE3 => X86Intrinsic::Sse3_MWait.index(),
X86IntrinsicGroup::SSSE3 => X86Intrinsic::Ssse3_PAlignr.index(),
X86IntrinsicGroup::SSE41 => X86Intrinsic::Sse41_PMovZXWQ.index(),
X86IntrinsicGroup::SSE42 => X86Intrinsic::Sse42_Popcnt.index(),
X86IntrinsicGroup::AES => X86Intrinsic::Aes_PCLmulQDQ.index(),
X86IntrinsicGroup::SHA => X86Intrinsic::Sha_Sha256Msg2.index(),
X86IntrinsicGroup::RDRAND => X86Intrinsic::RdRand64.index(),
X86IntrinsicGroup::RDSEED => X86Intrinsic::RdSeed64.index(),
X86IntrinsicGroup::AVX => X86Intrinsic::Avx_MovntDQ256.index(),
X86IntrinsicGroup::AVX2 => X86Intrinsic::Avx2_PShufD256.index(),
X86IntrinsicGroup::FMA => X86Intrinsic::Fma_Fmsubadd231PD256.index(),
X86IntrinsicGroup::BMI => X86Intrinsic::Bmi_Tzcnt64.index(),
X86IntrinsicGroup::BMI2 => X86Intrinsic::Bmi2_Shrx64.index(),
X86IntrinsicGroup::ADX => X86Intrinsic::Adx_Adox64.index(),
X86IntrinsicGroup::CLFLUSHOPT => X86Intrinsic::Misc_Popcnt64.index(),
X86IntrinsicGroup::AVX512F => X86Intrinsic::Avx512_Rsqrt14SD.index(),
_ => X86Intrinsic::COUNT - 1,
}
}
#[cfg(test)]
mod extended_tests {
use super::*;
#[test]
fn test_index_ordering_is_chronological() {
assert!(X86Intrinsic::Sse_AddPS.index() < X86Intrinsic::Sse2_AddPD.index());
assert!(X86Intrinsic::Sse2_AddPD.index() < X86Intrinsic::Sse3_HAddPS.index());
assert!(X86Intrinsic::Sse3_HAddPS.index() < X86Intrinsic::Ssse3_PHAddW.index());
assert!(X86Intrinsic::Ssse3_PHAddW.index() < X86Intrinsic::Sse41_PMulLD.index());
assert!(X86Intrinsic::Sse41_PMulLD.index() < X86Intrinsic::Sse42_Crc32_8.index());
assert!(X86Intrinsic::Sse42_Crc32_8.index() < X86Intrinsic::Aes_AesEnc.index());
assert!(X86Intrinsic::Aes_AesEnc.index() < X86Intrinsic::Sha_Sha1Rnds4.index());
assert!(X86Intrinsic::Sha_Sha1Rnds4.index() < X86Intrinsic::RdRand16.index());
assert!(X86Intrinsic::RdRand16.index() < X86Intrinsic::Avx_AddPS256.index());
assert!(X86Intrinsic::Avx_AddPS256.index() < X86Intrinsic::Avx2_PAddB256.index());
assert!(X86Intrinsic::Avx2_PAddB256.index() < X86Intrinsic::Fma_Fmadd132PS.index());
assert!(X86Intrinsic::Fma_Fmadd132PS.index() < X86Intrinsic::Bmi_Andn32.index());
assert!(X86Intrinsic::Bmi_Andn32.index() < X86Intrinsic::Bmi2_Bzhi32.index());
assert!(X86Intrinsic::Bmi2_Bzhi32.index() < X86Intrinsic::Adx_Adcx32.index());
assert!(X86Intrinsic::Adx_Adcx32.index() < X86Intrinsic::Avx512_AddPS512.index());
}
#[test]
fn test_guess_group_accuracy() {
let table = X86IntrinsicTable::new();
let sse = table.lookup_by_enum(X86Intrinsic::Sse_AddPS).unwrap();
assert_eq!(sse.group, X86IntrinsicGroup::SSE);
let sse2 = table.lookup_by_enum(X86Intrinsic::Sse2_CvtPD2PS).unwrap();
assert_eq!(sse2.group, X86IntrinsicGroup::SSE2);
let avx = table.lookup_by_enum(X86Intrinsic::Avx_AddPS256).unwrap();
assert_eq!(avx.group, X86IntrinsicGroup::AVX);
let avx512f = table.lookup_by_enum(X86Intrinsic::Avx512_AddPS512).unwrap();
assert_eq!(avx512f.group, X86IntrinsicGroup::AVX512F);
let amx = table.lookup_by_enum(X86Intrinsic::Amx_TileLoadD).unwrap();
assert_eq!(amx.group, X86IntrinsicGroup::AMX);
}
#[test]
fn test_complex_feature_flags() {
let flag = X86IntrinsicGroup::MOVDIR.feature_flag();
assert!(flag.contains("movdiri"));
assert!(flag.contains("movdir64b"));
let flag = X86IntrinsicGroup::AMX.feature_flag();
assert!(flag.contains("amx-tile"));
}
#[test]
fn test_group_cardinalities_reasonable() {
let table = X86IntrinsicTable::new();
assert!(table.count_in_group(X86IntrinsicGroup::SSE) >= 10);
assert!(table.count_in_group(X86IntrinsicGroup::SSE2) >= 20);
assert!(table.count_in_group(X86IntrinsicGroup::AVX512DQ) >= 5);
assert!(table.count_in_group(X86IntrinsicGroup::AVX512BW) >= 4);
assert!(table.count_in_group(X86IntrinsicGroup::AVX512CD) <= 5);
assert!(table.count_in_group(X86IntrinsicGroup::AVX512ER) <= 5);
assert!(table.count_in_group(X86IntrinsicGroup::AVX512PF) <= 2);
}
#[test]
fn test_mask_variants_only_in_avx512_groups() {
let table = X86IntrinsicTable::new();
let avx512_groups: &[X86IntrinsicGroup] = &[
X86IntrinsicGroup::AVX512F,
X86IntrinsicGroup::AVX512CD,
X86IntrinsicGroup::AVX512BW,
X86IntrinsicGroup::AVX512DQ,
X86IntrinsicGroup::AVX512VL,
X86IntrinsicGroup::AVX512IFMA,
X86IntrinsicGroup::AVX512VBMI,
X86IntrinsicGroup::AVX512VBMI2,
X86IntrinsicGroup::AVX512VNNI,
X86IntrinsicGroup::AVX512BITALG,
X86IntrinsicGroup::AVX512VPOPCNTDQ,
X86IntrinsicGroup::AVX512BF16,
X86IntrinsicGroup::AVX512FP16,
];
for info in table.all() {
if info.has_mask_variant {
assert!(
avx512_groups.contains(&info.group),
"Intrinsic {:?} in group {:?} has mask variant but group is not AVX-512",
info.intrinsic,
info.group
);
}
}
}
#[test]
fn test_rounding_variants_in_avx512f_dq() {
let table = X86IntrinsicTable::new();
for info in table.all() {
if info.has_rounding_variant {
assert!(
matches!(
info.group,
X86IntrinsicGroup::AVX512F | X86IntrinsicGroup::AVX512DQ
),
"Intrinsic {:?} has rounding variant but is in group {:?}",
info.intrinsic,
info.group
);
}
}
}
#[test]
fn test_commutative_intrinsics_are_binary() {
let table = X86IntrinsicTable::new();
for info in table.all() {
if info.is_commutative {
assert_eq!(
info.num_operands, 2,
"Commutative intrinsic {:?} should have 2 operands, has {}",
info.intrinsic, info.num_operands
);
}
}
}
#[test]
fn test_side_effects_are_consistent() {
let table = X86IntrinsicTable::new();
for info in table.all() {
if info.side_effects != IntrinsicSideEffect::None {
let name = info.llvm_name;
let is_mem = name.contains("movnt")
|| name.contains("prefetch")
|| name.contains("clflush")
|| name.contains("clwb")
|| name.contains("monitor")
|| name.contains("mwait")
|| name.contains("clzero")
|| name.contains("xsave")
|| name.contains("xrstor")
|| name.contains("tileload")
|| name.contains("tilestore")
|| name.contains("tileconfig")
|| name.contains("gather");
if !is_mem {
assert!(
info.side_effects == IntrinsicSideEffect::Sync
|| name.contains("sfence")
|| name.contains("lfence")
|| name.contains("mfence"),
"Unexpected side effect {:?} for intrinsic {}",
info.side_effects,
name
);
}
}
}
}
#[test]
fn test_static_table_coherent() {
let lowering = X86IntrinsicLowering::new();
for &(intr, expected) in INTRINSIC_OPCODE_TABLE {
let actual = lowering.lower_to_opcode(intr);
assert_eq!(
actual, expected,
"Static table vs lowering mismatch for {:?}",
intr
);
}
}
#[test]
fn test_all_table_entries_have_valid_index() {
let table = X86IntrinsicTable::new();
for info in table.all() {
assert!(info.intrinsic.index() < X86Intrinsic::COUNT);
}
}
#[test]
fn test_intrinsic_name_prefixes() {
let table = X86IntrinsicTable::new();
for info in table.all() {
let name = info.llvm_name;
assert!(
name.starts_with("llvm.x86.") || name.contains(".auto"),
"Intrinsic {:?} has unexpected name: {}",
info.intrinsic,
name
);
}
}
#[test]
fn test_emitter_output_format() {
let emitter = X86IntrinsicEmitter::new();
let call = emitter.emit_call(X86Intrinsic::Sse_AddPS, &["%a".into(), "%b".into()]);
assert!(call.starts_with("<4 x f32> @llvm.x86.sse.add.ps"));
let call = emitter.emit_call(X86Intrinsic::Sse2_AddPD, &["%a".into(), "%b".into()]);
assert!(call.starts_with("<2 x f64> @llvm.x86.sse2.add.pd"));
let call = emitter.emit_call(X86Intrinsic::Avx_AddPS256, &["%a".into(), "%b".into()]);
assert!(call.starts_with("<8 x f32> @llvm.x86.avx.add.ps.256"));
let call = emitter.emit_call(X86Intrinsic::Avx512_AddPS512, &["%a".into(), "%b".into()]);
assert!(call.starts_with("<16 x f32> @llvm.x86.avx512.add.ps.512"));
let call = emitter.emit_call(X86Intrinsic::Aes_AesEnc, &["%a".into(), "%b".into()]);
assert!(call.starts_with("<2 x i64> @llvm.x86.aesni.aesenc"));
let call = emitter.emit_call(
X86Intrinsic::Sha_Sha1Rnds4,
&["%a".into(), "%b".into(), "%c".into()],
);
assert!(call.contains("llvm.x86.sha1rnds4"));
let call = emitter.emit_call(X86Intrinsic::Bmi_Andn32, &["%a".into(), "%b".into()]);
assert!(call.starts_with("i32 @llvm.x86.bmi.andn.32"));
let call = emitter.emit_call(
X86Intrinsic::Fma_Fmadd132PS,
&["%a".into(), "%b".into(), "%c".into()],
);
assert!(call.starts_with("<4 x f32> @llvm.x86.fma.fmadd.132.ps"));
}
#[test]
fn test_expand_inline_comprehensive() {
let l = X86IntrinsicLowering::new();
assert!(l.can_expand_inline(X86Intrinsic::Avx_ZeroAll));
assert!(l.can_expand_inline(X86Intrinsic::Avx_ZeroUpper));
assert!(l.can_expand_inline(X86Intrinsic::Misc_Monitorx));
assert!(l.can_expand_inline(X86Intrinsic::Misc_MWaitx));
assert!(l.can_expand_inline(X86Intrinsic::Misc_Clzero));
assert!(l.can_expand_inline(X86Intrinsic::Amx_TileConfig));
assert!(l.can_expand_inline(X86Intrinsic::Amx_TileRelease));
assert!(!l.can_expand_inline(X86Intrinsic::Sse_AddPS));
assert!(!l.can_expand_inline(X86Intrinsic::Sse2_AddPD));
assert!(!l.can_expand_inline(X86Intrinsic::Avx512_AddPS512));
assert!(!l.can_expand_inline(X86Intrinsic::Fma_Fmadd132PS));
assert!(!l.can_expand_inline(X86Intrinsic::Aes_AesEnc));
}
#[test]
fn test_verifier_complex_features() {
let v = X86IntrinsicVerifier::new(
vec![
"+avx512f".into(),
"+avx512dq".into(),
"+avx512bw".into(),
"+avx512vnni".into(),
],
true,
);
assert_eq!(v.verify(X86Intrinsic::Avx512_AddPS512, 2), Verdict::Valid);
assert_eq!(v.verify(X86Intrinsic::Avx512_PAddD512, 2), Verdict::Valid);
assert_eq!(v.verify(X86Intrinsic::Avx512_PAddB512, 2), Verdict::Valid);
assert_eq!(v.verify(X86Intrinsic::Avx512_VPDPBUSD, 3), Verdict::Valid);
}
#[test]
fn test_lowering_group_of() {
let l = X86IntrinsicLowering::new();
assert_eq!(
l.group_of(X86Intrinsic::Sse_AddPS),
Some(X86IntrinsicGroup::SSE)
);
assert_eq!(
l.group_of(X86Intrinsic::Sse2_AddPD),
Some(X86IntrinsicGroup::SSE2)
);
assert_eq!(
l.group_of(X86Intrinsic::Sse3_HAddPS),
Some(X86IntrinsicGroup::SSE3)
);
assert_eq!(
l.group_of(X86Intrinsic::Ssse3_PHAddW),
Some(X86IntrinsicGroup::SSSE3)
);
assert_eq!(
l.group_of(X86Intrinsic::Sse41_PMulLD),
Some(X86IntrinsicGroup::SSE41)
);
assert_eq!(
l.group_of(X86Intrinsic::Sse42_Crc32_8),
Some(X86IntrinsicGroup::SSE42)
);
assert_eq!(
l.group_of(X86Intrinsic::Aes_AesEnc),
Some(X86IntrinsicGroup::AES)
);
assert_eq!(
l.group_of(X86Intrinsic::Sha_Sha1Rnds4),
Some(X86IntrinsicGroup::SHA)
);
assert_eq!(
l.group_of(X86Intrinsic::RdRand32),
Some(X86IntrinsicGroup::RDRAND)
);
assert_eq!(
l.group_of(X86Intrinsic::RdSeed32),
Some(X86IntrinsicGroup::RDSEED)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx_AddPS256),
Some(X86IntrinsicGroup::AVX)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx2_PAddB256),
Some(X86IntrinsicGroup::AVX2)
);
assert_eq!(
l.group_of(X86Intrinsic::Fma_Fmadd132PS),
Some(X86IntrinsicGroup::FMA)
);
assert_eq!(
l.group_of(X86Intrinsic::Bmi_Andn32),
Some(X86IntrinsicGroup::BMI)
);
assert_eq!(
l.group_of(X86Intrinsic::Bmi2_Bzhi32),
Some(X86IntrinsicGroup::BMI2)
);
assert_eq!(
l.group_of(X86Intrinsic::Adx_Adcx32),
Some(X86IntrinsicGroup::ADX)
);
assert_eq!(
l.group_of(X86Intrinsic::Misc_Clflushopt),
Some(X86IntrinsicGroup::CLFLUSHOPT)
);
assert_eq!(
l.group_of(X86Intrinsic::Misc_Lzcnt32),
Some(X86IntrinsicGroup::LZCNT)
);
assert_eq!(
l.group_of(X86Intrinsic::Misc_Popcnt32),
Some(X86IntrinsicGroup::POPCNT)
);
assert_eq!(
l.group_of(X86Intrinsic::Misc_XSave),
Some(X86IntrinsicGroup::XSAVE)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_AddPS512),
Some(X86IntrinsicGroup::AVX512F)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_ConflictD512),
Some(X86IntrinsicGroup::AVX512CD)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_Exp2PS512),
Some(X86IntrinsicGroup::AVX512ER)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_PAddB512),
Some(X86IntrinsicGroup::AVX512BW)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_PAddD512),
Some(X86IntrinsicGroup::AVX512DQ)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_VPMadd52LUQ),
Some(X86IntrinsicGroup::AVX512IFMA)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_PermB),
Some(X86IntrinsicGroup::AVX512VBMI)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_PExpandB),
Some(X86IntrinsicGroup::AVX512VBMI2)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_VPDPBUSD),
Some(X86IntrinsicGroup::AVX512VNNI)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_VPopcntB),
Some(X86IntrinsicGroup::AVX512BITALG)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_DPBf16PS),
Some(X86IntrinsicGroup::AVX512BF16)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_AddPH),
Some(X86IntrinsicGroup::AVX512FP16)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_VAesEnc),
Some(X86IntrinsicGroup::AVX512VAES)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_VGF2P8AffineQB),
Some(X86IntrinsicGroup::AVX512GFNI)
);
assert_eq!(
l.group_of(X86Intrinsic::Avx512_VP2IntersectD),
Some(X86IntrinsicGroup::AVX512VP2INTERSECT)
);
assert_eq!(
l.group_of(X86Intrinsic::Amx_TileLoadD),
Some(X86IntrinsicGroup::AMX)
);
}
#[test]
fn test_lookup_opcode_from_table_helper() {
assert_eq!(
lookup_opcode_from_table(X86Intrinsic::Sse_AddPS),
Some(X86Opcode::ADDPS)
);
assert_eq!(
lookup_opcode_from_table(X86Intrinsic::Aes_AesEnc),
Some(X86Opcode::AESENC)
);
assert_eq!(
lookup_opcode_from_table(X86Intrinsic::Sse2_PShufD),
Some(X86Opcode::PSHUFD)
);
assert_eq!(lookup_opcode_from_table(X86Intrinsic::Sse42_Popcnt), None);
}
#[test]
fn test_sync_intrinsics_have_no_operands() {
let table = X86IntrinsicTable::new();
for info in table.all() {
if info.side_effects == IntrinsicSideEffect::Sync {
assert_eq!(
info.num_operands, 0,
"Sync intrinsic {:?} should have 0 operands",
info.intrinsic
);
}
}
}
}
pub fn intrinsic_name(intr: X86Intrinsic) -> Option<&'static str> {
X86IntrinsicTable::new()
.lookup_by_enum(intr)
.map(|i| i.llvm_name)
}
pub fn intrinsic_group(intr: X86Intrinsic) -> Option<X86IntrinsicGroup> {
X86IntrinsicTable::new()
.lookup_by_enum(intr)
.map(|i| i.group)
}
pub fn intrinsic_feature(intr: X86Intrinsic) -> Option<&'static str> {
X86IntrinsicTable::new()
.lookup_by_enum(intr)
.map(|i| i.min_feature)
}
pub fn intrinsic_reads_memory(intr: X86Intrinsic) -> bool {
X86IntrinsicTable::new()
.lookup_by_enum(intr)
.map(|i| {
matches!(
i.side_effects,
IntrinsicSideEffect::ReadMem | IntrinsicSideEffect::ReadWriteMem
)
})
.unwrap_or(false)
}
pub fn intrinsic_writes_memory(intr: X86Intrinsic) -> bool {
X86IntrinsicTable::new()
.lookup_by_enum(intr)
.map(|i| {
matches!(
i.side_effects,
IntrinsicSideEffect::WriteMem | IntrinsicSideEffect::ReadWriteMem
)
})
.unwrap_or(false)
}
pub fn intrinsic_operand_count(intr: X86Intrinsic) -> Option<usize> {
X86IntrinsicTable::new()
.lookup_by_enum(intr)
.map(|i| i.num_operands)
}
#[cfg(test)]
mod api_tests {
use super::*;
#[test]
fn test_intrinsic_name_known() {
assert_eq!(
intrinsic_name(X86Intrinsic::Sse_AddPS),
Some("llvm.x86.sse.add.ps")
);
}
#[test]
fn test_intrinsic_group_known() {
assert_eq!(
intrinsic_group(X86Intrinsic::Sse2_AddPD),
Some(X86IntrinsicGroup::SSE2)
);
assert_eq!(
intrinsic_group(X86Intrinsic::Avx512_AddPS512),
Some(X86IntrinsicGroup::AVX512F)
);
}
#[test]
fn test_intrinsic_feature_known() {
assert_eq!(intrinsic_feature(X86Intrinsic::Sse_AddPS), Some("+sse"));
assert_eq!(
intrinsic_feature(X86Intrinsic::Avx512_AddPS512),
Some("+avx512f")
);
}
#[test]
fn test_intrinsic_memory_flags() {
assert!(!intrinsic_reads_memory(X86Intrinsic::Sse_AddPS));
assert!(!intrinsic_writes_memory(X86Intrinsic::Sse_AddPS));
assert!(intrinsic_writes_memory(X86Intrinsic::Sse_MovntPS));
assert!(intrinsic_writes_memory(X86Intrinsic::Amx_TileStoreD));
}
#[test]
fn test_intrinsic_operand_count_api() {
assert_eq!(intrinsic_operand_count(X86Intrinsic::Sse_AddPS), Some(2));
assert_eq!(intrinsic_operand_count(X86Intrinsic::Sse_SqrtPS), Some(1));
assert_eq!(
intrinsic_operand_count(X86Intrinsic::Fma_Fmadd132PS),
Some(3)
);
assert_eq!(
intrinsic_operand_count(X86Intrinsic::Avx2_GatherDPS),
Some(5)
);
assert_eq!(intrinsic_operand_count(X86Intrinsic::Sse_Sfence), Some(0));
}
#[test]
fn test_intrinsic_name_all_have_prefix() {
for idx in 0..X86Intrinsic::COUNT {
let intr: X86Intrinsic = unsafe { std::mem::transmute(idx as u16) };
if let Some(name) = intrinsic_name(intr) {
assert!(
name.starts_with("llvm.x86.") || name.contains(".auto"),
"Intrinsic {:?} has name: {}",
intr,
name
);
}
}
}
#[test]
fn test_feature_for_all_groups() {
let groups_with_features: &[X86IntrinsicGroup] = &[
X86IntrinsicGroup::SSE,
X86IntrinsicGroup::SSE2,
X86IntrinsicGroup::SSE3,
X86IntrinsicGroup::SSSE3,
X86IntrinsicGroup::SSE41,
X86IntrinsicGroup::SSE42,
X86IntrinsicGroup::AVX,
X86IntrinsicGroup::AVX2,
X86IntrinsicGroup::FMA,
X86IntrinsicGroup::BMI,
X86IntrinsicGroup::BMI2,
X86IntrinsicGroup::ADX,
X86IntrinsicGroup::AES,
X86IntrinsicGroup::SHA,
X86IntrinsicGroup::RDRAND,
X86IntrinsicGroup::RDSEED,
X86IntrinsicGroup::CLFLUSHOPT,
X86IntrinsicGroup::LZCNT,
X86IntrinsicGroup::POPCNT,
X86IntrinsicGroup::XSAVE,
X86IntrinsicGroup::MOVDIR,
X86IntrinsicGroup::AVX512F,
X86IntrinsicGroup::AVX512CD,
X86IntrinsicGroup::AVX512ER,
X86IntrinsicGroup::AVX512PF,
X86IntrinsicGroup::AVX512BW,
X86IntrinsicGroup::AVX512DQ,
X86IntrinsicGroup::AVX512VL,
X86IntrinsicGroup::AVX512IFMA,
X86IntrinsicGroup::AVX512VBMI,
X86IntrinsicGroup::AVX512VBMI2,
X86IntrinsicGroup::AVX512VNNI,
X86IntrinsicGroup::AVX512BITALG,
X86IntrinsicGroup::AVX512VPOPCNTDQ,
X86IntrinsicGroup::AVX512BF16,
X86IntrinsicGroup::AVX512FP16,
X86IntrinsicGroup::AVX512VAES,
X86IntrinsicGroup::AVX512GFNI,
X86IntrinsicGroup::AVX512VP2INTERSECT,
X86IntrinsicGroup::AMX,
];
for &group in groups_with_features {
assert!(
!group.feature_flag().is_empty(),
"Group {:?} has empty feature flag",
group
);
}
}
#[test]
fn test_as_str_roundtrip() {
let all_groups: &[X86IntrinsicGroup] = &[
X86IntrinsicGroup::SSE,
X86IntrinsicGroup::SSE2,
X86IntrinsicGroup::SSE3,
X86IntrinsicGroup::SSSE3,
X86IntrinsicGroup::SSE41,
X86IntrinsicGroup::SSE42,
X86IntrinsicGroup::AVX,
X86IntrinsicGroup::AVX2,
X86IntrinsicGroup::FMA,
X86IntrinsicGroup::BMI,
X86IntrinsicGroup::BMI2,
X86IntrinsicGroup::ADX,
X86IntrinsicGroup::AES,
X86IntrinsicGroup::SHA,
X86IntrinsicGroup::RDRAND,
X86IntrinsicGroup::RDSEED,
X86IntrinsicGroup::CLFLUSHOPT,
X86IntrinsicGroup::LZCNT,
X86IntrinsicGroup::POPCNT,
X86IntrinsicGroup::XSAVE,
X86IntrinsicGroup::MOVDIR,
X86IntrinsicGroup::AVX512F,
X86IntrinsicGroup::AVX512CD,
X86IntrinsicGroup::AVX512ER,
X86IntrinsicGroup::AVX512PF,
X86IntrinsicGroup::AVX512BW,
X86IntrinsicGroup::AVX512DQ,
X86IntrinsicGroup::AVX512VL,
X86IntrinsicGroup::AVX512IFMA,
X86IntrinsicGroup::AVX512VBMI,
X86IntrinsicGroup::AVX512VBMI2,
X86IntrinsicGroup::AVX512VNNI,
X86IntrinsicGroup::AVX512BITALG,
X86IntrinsicGroup::AVX512VPOPCNTDQ,
X86IntrinsicGroup::AVX512BF16,
X86IntrinsicGroup::AVX512FP16,
X86IntrinsicGroup::AVX512VAES,
X86IntrinsicGroup::AVX512GFNI,
X86IntrinsicGroup::AVX512VP2INTERSECT,
X86IntrinsicGroup::AMX,
X86IntrinsicGroup::Misc,
];
for &group in all_groups {
let s = group.as_str();
assert!(!s.is_empty(), "Group {:?} has empty as_str()", group);
}
}
#[test]
fn test_ret_type_desc_all_variants_have_string() {
let types: &[RetTypeDesc] = &[
RetTypeDesc::Void,
RetTypeDesc::I1,
RetTypeDesc::I8,
RetTypeDesc::I16,
RetTypeDesc::I32,
RetTypeDesc::I64,
RetTypeDesc::I128,
RetTypeDesc::F32,
RetTypeDesc::F64,
RetTypeDesc::V2F64,
RetTypeDesc::V4F32,
RetTypeDesc::V8F32,
RetTypeDesc::V16F32,
RetTypeDesc::V2I64,
RetTypeDesc::V4I32,
RetTypeDesc::V8I16,
RetTypeDesc::V16I8,
RetTypeDesc::V4F64,
RetTypeDesc::V8I32,
RetTypeDesc::V16I16,
RetTypeDesc::V32I8,
RetTypeDesc::V8F64,
RetTypeDesc::V16I32,
RetTypeDesc::V32I16,
RetTypeDesc::V64I8,
RetTypeDesc::SameAsOp0,
];
for t in types {
assert!(!t.to_type_str().is_empty(), "{:?} has empty type string", t);
}
}
#[test]
fn test_side_effect_discriminant_values() {
assert_ne!(IntrinsicSideEffect::None, IntrinsicSideEffect::ReadMem);
assert_ne!(IntrinsicSideEffect::ReadMem, IntrinsicSideEffect::WriteMem);
assert_ne!(
IntrinsicSideEffect::WriteMem,
IntrinsicSideEffect::ReadWriteMem
);
assert_ne!(IntrinsicSideEffect::ReadWriteMem, IntrinsicSideEffect::Sync);
}
#[test]
fn test_align_info_default() {
let a = AlignInfo::default();
assert_eq!(a.min_align_bytes, 0);
assert_eq!(a.prefer_align_bytes, 0);
}
#[test]
fn test_verdict_equality() {
assert_eq!(Verdict::Valid, Verdict::Valid);
assert_ne!(
Verdict::Valid,
Verdict::Invalid {
reason: "test".into()
}
);
}
#[test]
fn test_emitter_default() {
let emitter = X86IntrinsicEmitter::default();
assert!(emitter.table().len() > 0);
}
#[test]
fn test_verifier_default() {
let v = X86IntrinsicVerifier::default();
assert_eq!(v.features(), &["+sse2".to_string()]);
}
#[test]
fn test_lowering_default() {
let l = X86IntrinsicLowering::default();
assert!(l.table().len() > 0);
}
#[test]
fn test_table_default() {
let t = X86IntrinsicTable::default();
assert!(t.len() > 0);
}
#[test]
fn test_all_intrinsics_have_lowering_or_none() {
let lowering = X86IntrinsicLowering::new();
for idx in 0..X86Intrinsic::COUNT {
let intr: X86Intrinsic = unsafe { std::mem::transmute(idx as u16) };
let _ = lowering.lower_to_opcode(intr);
}
}
#[test]
fn test_all_intrinsics_verifiable() {
let v = X86IntrinsicVerifier::default();
for idx in 0..X86Intrinsic::COUNT {
let intr: X86Intrinsic = unsafe { std::mem::transmute(idx as u16) };
let _ = v.verify(intr, 2);
}
}
#[test]
fn test_all_intrinsics_emittable() {
let emitter = X86IntrinsicEmitter::new();
for idx in 0..X86Intrinsic::COUNT {
let intr: X86Intrinsic = unsafe { std::mem::transmute(idx as u16) };
let call = emitter.emit_call(intr, &[]);
assert!(!call.is_empty());
}
}
#[test]
fn test_intrinsic_count_matches_enum() {
let last = X86Intrinsic::Amx_TDPFP16PS;
assert_eq!(last.index() + 1, X86Intrinsic::COUNT);
}
}