mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 13:00:15 +02:00
Audit the code base and mark any instruction that implicitly clobbers flags so it can get special handling in the dispatcher to spill NZCV ahead of emitting. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
2258 lines
101 KiB
JSON
2258 lines
101 KiB
JSON
{
|
|
"Docs": [
|
|
"IRTypes define types that can be used directly in the IR.",
|
|
"These will translate to the underlying C types when stored in the op data",
|
|
"",
|
|
"SSA types are special cased",
|
|
" SSA = untyped",
|
|
" GPR = GPR class type",
|
|
" FPR = FPR class type",
|
|
"Declaring the SSA types correctly will allow validation passes to ensure the op is getting passed correct arguments",
|
|
"",
|
|
"Arguments must always follow a particular order. <Type>:<Prefix><Name>",
|
|
"Type must always be an IRType",
|
|
"Prefix currently can be one of the following: #, $",
|
|
" #: This is a temporary argument that is in the IR Emitter arguments",
|
|
" - This will not be stored in the resulting IR op data structure",
|
|
" $: This is a value that will be stored inside of the IR op data structure",
|
|
" - If it is type SSA, GPR, or FPR then it is an SSA type",
|
|
" - These will get added to the SSA argument union to ensure RA happens",
|
|
"",
|
|
"IR op definition follows the structure of <SSA Type> = <IROp> <Arguments>",
|
|
"",
|
|
"Eg:",
|
|
"IR op with no result and no arguments",
|
|
" CallbackReturn",
|
|
"",
|
|
"IR op with result and no arguments",
|
|
" GPR = ProcessorID",
|
|
"",
|
|
"IR op with no result and non-SSA argument",
|
|
" Fence FenceType:$Type",
|
|
"",
|
|
"IR op with no result and SSA arguments",
|
|
" SetRoundingMode GPR:$Mode",
|
|
"",
|
|
"IR op with result and SSA arguments",
|
|
" GPR = Add GPR:$Src1, GPR:$Src2",
|
|
|
|
"",
|
|
"## Op members ##",
|
|
"* Desc",
|
|
" * List of text for documenting this IR op.",
|
|
"* OpClass",
|
|
" * Textual class to group IR ops by type",
|
|
"* DestClass",
|
|
" * SSA class of the return when the return type is `SSA`",
|
|
" * Not used if the destination type is one of {GPR, GPRPair, FPR}",
|
|
"* DestSize",
|
|
" * The size of the destination type",
|
|
"* EmitValidation",
|
|
" * List of validations to emit for the IR emitter",
|
|
" * These are validations that can't be automatically inferred and need to be hand-written",
|
|
""
|
|
],
|
|
"Defines": [
|
|
"constexpr uint8_t COND_EQ = 0",
|
|
"constexpr uint8_t COND_NEQ = 1",
|
|
"constexpr uint8_t COND_UGE = 2",
|
|
"constexpr uint8_t COND_ULT = 3",
|
|
"constexpr uint8_t COND_MI = 4",
|
|
"constexpr uint8_t COND_PL = 5",
|
|
"constexpr uint8_t COND_VS = 6",
|
|
"constexpr uint8_t COND_VC = 7",
|
|
"constexpr uint8_t COND_UGT = 8",
|
|
"constexpr uint8_t COND_ULE = 9",
|
|
"constexpr uint8_t COND_SGE = 10",
|
|
"constexpr uint8_t COND_SLT = 11",
|
|
"constexpr uint8_t COND_SGT = 12",
|
|
"constexpr uint8_t COND_SLE = 13",
|
|
"constexpr uint8_t COND_ANDZ = 14 /* (a & b) == 0 */",
|
|
"constexpr uint8_t COND_ANDNZ = 15 /* (a & b) != 0 */",
|
|
|
|
"constexpr uint8_t COND_FLU = 16 /* float less or unordred */",
|
|
"constexpr uint8_t COND_FGE = 17 /* float greater or equal */",
|
|
"constexpr uint8_t COND_FLEU = 18 /* float less or equal or unordred */",
|
|
"constexpr uint8_t COND_FGT = 19 /* float greater */",
|
|
"constexpr uint8_t COND_FU = 20 /* float unordred */",
|
|
"constexpr uint8_t COND_FNU = 21 /* float not unordred */",
|
|
|
|
"constexpr FEXCore::IR::RegisterClassType GPRClass {0}",
|
|
"constexpr FEXCore::IR::RegisterClassType GPRFixedClass {1}",
|
|
"constexpr FEXCore::IR::RegisterClassType FPRClass {2}",
|
|
"constexpr FEXCore::IR::RegisterClassType FPRFixedClass {3}",
|
|
"constexpr FEXCore::IR::RegisterClassType GPRPairClass {4}",
|
|
"constexpr FEXCore::IR::RegisterClassType ComplexClass {5}",
|
|
"constexpr FEXCore::IR::RegisterClassType InvalidClass {7}",
|
|
"",
|
|
"// Only up to 30 registers per register class",
|
|
"constexpr uint8_t InvalidReg {31}",
|
|
"",
|
|
"constexpr FEXCore::IR::TypeDefinition i8 {TypeDefinition::Create(1, 0)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i16 {TypeDefinition::Create(2, 0)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i32 {TypeDefinition::Create(4, 0)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i64 {TypeDefinition::Create(8, 0)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i128 {TypeDefinition::Create(16, 0)}",
|
|
"",
|
|
"constexpr FEXCore::IR::TypeDefinition i8v8 {TypeDefinition::Create(1, 8)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i8v16 {TypeDefinition::Create(1, 16)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i16v4 {TypeDefinition::Create(2, 4)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i16v8 {TypeDefinition::Create(2, 8)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i32v2 {TypeDefinition::Create(4, 2)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i32v4 {TypeDefinition::Create(4, 4)}",
|
|
"constexpr FEXCore::IR::TypeDefinition i64v2 {TypeDefinition::Create(8, 2)}",
|
|
"",
|
|
"constexpr uint8_t FCMP_FLAG_EQ = 0",
|
|
"constexpr uint8_t FCMP_FLAG_LT = 1",
|
|
"constexpr uint8_t FCMP_FLAG_UNORDERED = 2",
|
|
|
|
"constexpr FEXCore::IR::FenceType Fence_Load {0}",
|
|
"constexpr FEXCore::IR::FenceType Fence_Store {1}",
|
|
"constexpr FEXCore::IR::FenceType Fence_LoadStore {2}",
|
|
|
|
"constexpr uint8_t ROUND_MODE_NEAREST = 0",
|
|
"constexpr uint8_t ROUND_MODE_NEGATIVE_INFINITY = 1",
|
|
"constexpr uint8_t ROUND_MODE_POSITIVE_INFINITY = 2",
|
|
"constexpr uint8_t ROUND_MODE_TOWARDS_ZERO = 3",
|
|
"constexpr uint8_t ROUND_MODE_FLUSH_TO_ZERO = 1 << 2",
|
|
|
|
"constexpr FEXCore::IR::RoundType Round_Nearest {ROUND_MODE_NEAREST}",
|
|
"constexpr FEXCore::IR::RoundType Round_Negative_Infinity {ROUND_MODE_NEGATIVE_INFINITY}",
|
|
"constexpr FEXCore::IR::RoundType Round_Positive_Infinity {ROUND_MODE_POSITIVE_INFINITY}",
|
|
"constexpr FEXCore::IR::RoundType Round_Towards_Zero {ROUND_MODE_TOWARDS_ZERO} /* Truncate */",
|
|
"constexpr FEXCore::IR::RoundType Round_Host {ROUND_MODE_TOWARDS_ZERO + 1}",
|
|
|
|
"constexpr FEXCore::IR::MemOffsetType MEM_OFFSET_SXTX {0}",
|
|
"constexpr FEXCore::IR::MemOffsetType MEM_OFFSET_UXTW {1}",
|
|
"constexpr FEXCore::IR::MemOffsetType MEM_OFFSET_SXTW {2}",
|
|
|
|
"struct BreakDefinition {",
|
|
" uint16_t ErrorRegister;",
|
|
" uint8_t Signal;",
|
|
" uint8_t TrapNumber;",
|
|
" uint8_t si_code;",
|
|
"};"
|
|
],
|
|
"IRTypes" : {
|
|
"i1": "bool",
|
|
"i8": "int8_t",
|
|
"i16": "int16_t",
|
|
"i32": "int32_t",
|
|
"i64": "int64_t",
|
|
"u8": "uint8_t",
|
|
"u16": "uint16_t",
|
|
"u32": "uint32_t",
|
|
"u64": "uint64_t",
|
|
"OpSize": "FEXCore::IR::OpSize",
|
|
"SSA": "OrderedNode*",
|
|
"GPR": "OrderedNode*",
|
|
"GPRPair": "OrderedNode*",
|
|
"FPR": "OrderedNode*",
|
|
"FenceType": "FenceType",
|
|
"RegisterClass": "RegisterClassType",
|
|
"CondClass": "CondClassType",
|
|
"SyscallFlags": "FEXCore::IR::SyscallFlags",
|
|
"SHA256Sum": "SHA256Sum",
|
|
"MemOffsetType": "MemOffsetType",
|
|
"BreakDefinition": "BreakDefinition",
|
|
"RoundType": "RoundType",
|
|
"FloatCompareOp": "FloatCompareOp",
|
|
"NamedVectorConstant": "FEXCore::IR::NamedVectorConstant",
|
|
"IndexNamedVectorConstant": "FEXCore::IR::IndexNamedVectorConstant"
|
|
},
|
|
"Ops": {
|
|
"Misc": {
|
|
"Dummy": {
|
|
"HasSideEffects": true,
|
|
"SwitchGen": false,
|
|
"JITDispatchOverride": "NoOp"
|
|
},
|
|
"IRHeader SSA:$Blocks, u64:$OriginalRIP, u32:$BlockCount, u32:$NumHostInstructions": {
|
|
"SwitchGen": false,
|
|
"JITDispatchOverride": "NoOp"
|
|
},
|
|
"CodeBlock SSA:$Begin, SSA:$Last": {
|
|
"SwitchGen": false,
|
|
"RAOverride": "0",
|
|
"JITDispatchOverride": "NoOp"
|
|
},
|
|
"BeginBlock SSA:$BlockHeader": {
|
|
"HasSideEffects": true,
|
|
"SwitchGen": false,
|
|
"RAOverride": "0",
|
|
"JITDispatchOverride": "NoOp"
|
|
},
|
|
"InvalidateFlags u64:$Flags": {
|
|
"HasSideEffects": true,
|
|
"JITDispatchOverride": "NoOp"
|
|
},
|
|
|
|
"EndBlock SSA:$BlockHeader": {
|
|
"HasSideEffects": true,
|
|
"SwitchGen": false,
|
|
"RAOverride": "0",
|
|
"JITDispatchOverride": "NoOp"
|
|
},
|
|
|
|
"GuestOpcode u32:$GuestEntryOffset": {
|
|
"Desc": ["Marks the beginning of a guest opcode"],
|
|
"HasSideEffects": true
|
|
},
|
|
|
|
"GPR = ValidateCode u64:$CodeOriginalLow, u64:$CodeOriginalhigh, i64:$Offset, u8:$CodeLength": {
|
|
"HasSideEffects": true,
|
|
"HasDest": true,
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "8"
|
|
},
|
|
|
|
"ThreadRemoveCodeEntry": {
|
|
"HasSideEffects": true
|
|
},
|
|
|
|
"GPR = ProcessorID": {
|
|
"Desc": ["Returns the processor ID correlating to the current running CPU",
|
|
"This may be out of date by time this instruction is executed so care must be taken",
|
|
"This same information can be gotten from syscall getcpu(&cpu, &node)",
|
|
"uint32_t Res = (node << 12) | cpu;",
|
|
"This means it has a limitation of 4096 CPU cores. Which is fine and matches x86 behaviour"
|
|
],
|
|
"DestSize": 8
|
|
},
|
|
"GPR = GetRoundingMode": {
|
|
"Desc": ["Gets the current rounding mode options"
|
|
],
|
|
"DestSize": "4"
|
|
},
|
|
|
|
"SetRoundingMode GPR:$RoundMode": {
|
|
"Desc": ["Sets the current rounding mode options for the thread"
|
|
],
|
|
"HasSideEffects": true
|
|
},
|
|
"Print SSA:$Value": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Debug operation that prints an SSA value to the console",
|
|
"May only print 64bits of the value",
|
|
"Depending on backend, may only support GPR printing"
|
|
],
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Value) != GPRPairClass"
|
|
]
|
|
},
|
|
"GPRPair = RDRAND i1:$GetReseeded": {
|
|
"Desc": ["Uses the hardware random number generator to generate a 64bit number",
|
|
"The boolean argument asks if we should be reading the reseeded number or not",
|
|
"Reseeded RNG calculation is more expensive and will be heavier to use",
|
|
"The first GPR pair element is the 64-bit number",
|
|
"The second GPR pair element is a bool if the number is valid",
|
|
"RNG hardware is allowed to fail early and return. Software must always check this"
|
|
],
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "16",
|
|
"NumElements": "2"
|
|
},
|
|
"Yield": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["This is a hint instruction that the CPU is likely to do a spin so it might want to pause to help out SMP",
|
|
"Can be implemented as a NOP if necessary"]
|
|
}
|
|
},
|
|
"Branch": {
|
|
"Jump SSA:$TargetBlock": {
|
|
"HasSideEffects": true,
|
|
"RAOverride": "0"
|
|
},
|
|
"CondJump SSA:$Cmp1, SSA:$Cmp2, SSA:$TrueBlock, SSA:$FalseBlock, CondClass:$Cond{{COND_NEQ}}, u8:$CompareSize{0}": {
|
|
"HasSideEffects": true,
|
|
"RAOverride": "2",
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Cmp1) == WalkFindRegClass($Cmp2)"
|
|
]
|
|
},
|
|
"ExitFunction GPR:$NewRIP": {
|
|
"Desc": ["Exits the current JIT function with a target RIP"
|
|
],
|
|
"HasSideEffects": true,
|
|
"DestSize": "GetOpSize(_NewRIP)"
|
|
},
|
|
"Break BreakDefinition:$Reason": {
|
|
"HasSideEffects": true
|
|
},
|
|
"CallbackReturn": {
|
|
"HasSideEffects": true
|
|
},
|
|
"GPR = Syscall GPR:$SyscallID, GPR:$Arg0, GPR:$Arg1, GPR:$Arg2, GPR:$Arg3, GPR:$Arg4, GPR:$Arg5, SyscallFlags:$Flags": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Dispatches a guest syscall through to the SyscallHandler class"
|
|
],
|
|
"DestSize": "8"
|
|
},
|
|
|
|
"GPR = InlineSyscall GPR:$Arg0, GPR:$Arg1, GPR:$Arg2, GPR:$Arg3, GPR:$Arg4, GPR:$Arg5, i32:$HostSyscallNumber, SyscallFlags:$Flags": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Dispatches a guest syscall directly to the host syscall interface,",
|
|
"bypassing the SyscallHandler class used by Syscall.",
|
|
"This has significantly less overhead than Syscall, which needs to save JIT state first.",
|
|
"Can only be used for syscalls that match across architecture,",
|
|
"such as gettid (matches on x86/x86-64/Arm64)."
|
|
],
|
|
|
|
"DestSize": "8"
|
|
},
|
|
|
|
"Thunk GPR:$ArgPtr, SHA256Sum:$ThunkNameHash": {
|
|
"HasSideEffects": true
|
|
},
|
|
|
|
"GPRPair = CPUID GPR:$Function, GPR:$Leaf": {
|
|
"Desc": ["Calls in to the CPUID handler function to return emulated CPUID",
|
|
"Returns a 128bit GPR pair that fits emulated EAX, EBX, EDX, ECX respectively"
|
|
],
|
|
"DestSize": "16",
|
|
"NumElements": "2"
|
|
},
|
|
"GPRPair = XGetBV GPR:$Function": {
|
|
"Desc": ["Calls in to the XCR handler function to return emulated XCR",
|
|
"Returns a 64bit GPR pair that fits emulated EAX, EDX respectively"
|
|
],
|
|
"DestSize": "8",
|
|
"NumElements": "2"
|
|
}
|
|
},
|
|
"Moves": {
|
|
"GPR = ExtractElementPair OpSize:#Size, GPRPair:$Pair, u8:$Element": {
|
|
"Desc": ["Extracts a register for the register pair"],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
|
|
"GPRPair = CreateElementPair OpSize:#Size, GPR:$Lower, GPR:$Upper": {
|
|
"Desc": ["Inserts a register for the register pair",
|
|
"ssa0 is the lower incoming register",
|
|
"ssa1 is the upper incoming register"
|
|
],
|
|
"DestSize": "Size",
|
|
"NumElements": "2",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i64Bit || Size == FEXCore::IR::OpSize::i128Bit"
|
|
]
|
|
}
|
|
},
|
|
"StaticRA": {
|
|
"SSA = LoadRegister i1:$IsAlias, u32:$Offset, RegisterClass:$Class, RegisterClass:$StaticClass, u8:#Size": {
|
|
"Desc": ["Loads a value from the static-ra context with offset",
|
|
"Dest = Ctx[Offset]"
|
|
],
|
|
"DestSize": "Size",
|
|
"DynamicDispatch": true
|
|
},
|
|
|
|
"StoreRegister SSA:$Value, i1:$IsPrewrite, u32:$Offset, RegisterClass:$Class, RegisterClass:$StaticClass, u8:#Size": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Stores a value to the static-ra context with offset",
|
|
"Ctx[Offset] = Value",
|
|
"Zero Extends if value's type is too small",
|
|
"Truncates if value's type is too large"
|
|
],
|
|
"DestSize": "Size",
|
|
"DynamicDispatch": true,
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Value) == $Class"
|
|
]
|
|
}
|
|
},
|
|
"Memory": {
|
|
"SSA = LoadContext u8:#ByteSize, RegisterClass:$Class, u32:$Offset": {
|
|
"Desc": ["Loads a value from the context with offset",
|
|
"Dest = Ctx[Offset]"
|
|
],
|
|
"DestSize": "ByteSize",
|
|
"EmitValidation": [
|
|
"($Class == GPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8)) || $Class == FPRClass",
|
|
"($Class == FPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8 || #ByteSize == 16 || #ByteSize == 32)) || $Class == GPRClass",
|
|
"!($Offset >= offsetof(Core::CPUState, gregs[0]) && $Offset < offsetof(Core::CPUState, gregs[16])) && \"Can't LoadContext to GPR\"",
|
|
"!($Offset >= offsetof(Core::CPUState, xmm.avx.data[0]) && $Offset < offsetof(Core::CPUState, xmm.avx.data[16])) && \"Can't LoadContext to XMM\""
|
|
]
|
|
},
|
|
|
|
"StoreContext u8:#ByteSize, RegisterClass:$Class, SSA:$Value, u32:$Offset": {
|
|
"Desc": ["Stores a value to the context with offset",
|
|
"Ctx[Offset] = Value",
|
|
"Zero Extends if value's type is too small",
|
|
"Truncates if value's type is too large"
|
|
],
|
|
"HasSideEffects": true,
|
|
"DestSize": "ByteSize",
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Value) == $Class",
|
|
"($Class == GPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8)) || $Class == FPRClass",
|
|
"($Class == FPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8 || #ByteSize == 16 || #ByteSize == 32)) || $Class == GPRClass",
|
|
"!($Offset >= offsetof(Core::CPUState, gregs[0]) && $Offset < offsetof(Core::CPUState, gregs[16])) && \"Can't StoreContext to GPR\"",
|
|
"!($Offset >= offsetof(Core::CPUState, xmm.avx.data[0]) && $Offset < offsetof(Core::CPUState, xmm.avx.data[16])) && \"Can't StoreContext to XMM\""
|
|
]
|
|
},
|
|
|
|
"SSA = LoadContextIndexed GPR:$Index, u8:#ByteSize, u32:$BaseOffset, u32:$Stride, RegisterClass:$Class": {
|
|
"Desc": ["Loads a value from the context with offset and indexed by SSA value",
|
|
"Dest = Ctx[BaseOffset + Index * Stride]"
|
|
],
|
|
"DestSize": "ByteSize",
|
|
"EmitValidation": [
|
|
"($Class == GPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8)) || $Class == FPRClass",
|
|
"($Class == FPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8 || #ByteSize == 16 || #ByteSize == 32)) || $Class == GPRClass",
|
|
"!($BaseOffset >= offsetof(Core::CPUState, gregs[0]) && $BaseOffset < offsetof(Core::CPUState, gregs[16])) && \"Can't LoadContextIndexed to GPR\"",
|
|
"!($BaseOffset >= offsetof(Core::CPUState, xmm.avx.data[0]) && $BaseOffset < offsetof(Core::CPUState, xmm.avx.data[16])) && \"Can't LoadContextIndexed to XMM\""
|
|
]
|
|
},
|
|
"StoreContextIndexed SSA:$Value, GPR:$Index, u8:#ByteSize, u32:$BaseOffset, u32:$Stride, RegisterClass:$Class": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Stores a value to the context with offset and indexed by SSA value",
|
|
"Ctx[BaseOffset + Index * Stride] = Value"
|
|
],
|
|
"DestSize": "ByteSize",
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Value) == $Class",
|
|
"($Class == GPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8)) || $Class == FPRClass",
|
|
"($Class == FPRClass && (#ByteSize == 1 || #ByteSize == 2 || #ByteSize == 4 || #ByteSize == 8 || #ByteSize == 16 || #ByteSize == 32)) || $Class == GPRClass",
|
|
"!($BaseOffset >= offsetof(Core::CPUState, gregs[0]) && $BaseOffset < offsetof(Core::CPUState, gregs[16])) && \"Can't StoreContextIndexed to GPR\"",
|
|
"!($BaseOffset >= offsetof(Core::CPUState, xmm.avx.data[0]) && $BaseOffset < offsetof(Core::CPUState, xmm.avx.data[16])) && \"Can't StoreContextIndexed to XMM\""
|
|
]
|
|
},
|
|
|
|
"SpillRegister SSA:$Value, u32:$Slot, RegisterClass:$Class": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Spills an SSA value to memory",
|
|
"Spill slots are register allocated and has live ranges calculated to handle slot calculation",
|
|
"```diff\n- !Don't use this op. It is for RA to handle spilling and filling!\n```"
|
|
],
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Value) == $Class"
|
|
]
|
|
},
|
|
|
|
"SSA = FillRegister SSA:$OriginalValue, u32:$Slot, RegisterClass:$Class": {
|
|
"Desc": ["Fills a register from a spill slot",
|
|
"Spill slots are register allocated and has live ranges calculated to handle slot calculation",
|
|
"```diff\n- !Don't use this op. It is for RA to handle spilling and filling!\n```",
|
|
"",
|
|
"The OriginalValue SSA arg points at the original SSA value spilled, and only exists for",
|
|
"RA validation purposes"
|
|
],
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($OriginalValue) == $Class"
|
|
]
|
|
},
|
|
|
|
"GPR = LoadFlag u32:$Flag": {
|
|
"Desc": ["Loads an x86-64 flag from the context object",
|
|
"Specialized to allow flexible implementation of flag handling"
|
|
],
|
|
"DestSize": "1"
|
|
},
|
|
|
|
"StoreFlag GPR:$Value, u32:$Flag": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Stores 1-bit of the flag in to the specified x86-64 flag",
|
|
"Specialized to allow flexible implementation of flag handling"
|
|
],
|
|
"DestSize": "1"
|
|
},
|
|
|
|
"GPR = GetHostFlag GPR:$Value, u8:$Flag": {
|
|
},
|
|
|
|
"SSA = LoadMem RegisterClass:$Class, u8:#Size, GPR:$Addr, GPR:$Offset, u8:$Align, MemOffsetType:$OffsetType, u8:$OffsetScale": {
|
|
"DestSize": "Size"
|
|
},
|
|
|
|
"StoreMem RegisterClass:$Class, u8:#Size, SSA:$Value, GPR:$Addr, GPR:$Offset, u8:$Align, MemOffsetType:$OffsetType, u8:$OffsetScale": {
|
|
"Desc": [ "Stores a value to memory.",
|
|
"Zero Extends if value's type is too small",
|
|
"Truncates if value's type is too large"
|
|
],
|
|
"HasSideEffects": true,
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Value) == $Class"
|
|
]
|
|
},
|
|
|
|
"SSA = LoadMemTSO RegisterClass:$Class, u8:#Size, GPR:$Addr, GPR:$Offset, u8:$Align, MemOffsetType:$OffsetType, u8:$OffsetScale": {
|
|
"Desc": ["Does a x86 TSO compatible load from memory. Offset must be Invalid()."
|
|
],
|
|
"DestSize": "Size",
|
|
"DynamicDispatch": true
|
|
},
|
|
|
|
"StoreMemTSO RegisterClass:$Class, u8:#Size, SSA:$Value, GPR:$Addr, GPR:$Offset, u8:$Align, MemOffsetType:$OffsetType, u8:$OffsetScale": {
|
|
"Desc": ["Does a x86 TSO compatible store to memory. Offset must be Invalid()."
|
|
],
|
|
"HasSideEffects": true,
|
|
"DestSize": "Size",
|
|
"DynamicDispatch": true,
|
|
"EmitValidation": [
|
|
"WalkFindRegClass($Value) == $Class"
|
|
]
|
|
},
|
|
|
|
"FPR = VLoadVectorMasked u8:#RegisterSize, u8:#ElementSize, FPR:$Mask, GPR:$Addr, GPR:$Offset, MemOffsetType:$OffsetType, u8:$OffsetScale": {
|
|
"Desc": ["Does a masked load similar to VPMASKMOV/VMASKMOV where the upper bit of each element",
|
|
"determines whether or not that element will be loaded from memory"],
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"VStoreVectorMasked u8:#RegisterSize, u8:#ElementSize, FPR:$Mask, FPR:$Data, GPR:$Addr, GPR:$Offset, MemOffsetType:$OffsetType, u8:$OffsetScale": {
|
|
"Desc": ["Does a masked store similar to VPMASKMOV/VMASKMOV where the upper bit of each element",
|
|
"determines whether or not that element will be stored to memory"],
|
|
"HasSideEffects": true,
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VLoadVectorElement u8:#RegisterSize, u8:#ElementSize, FPR:$DstSrc, u8:$Index, GPR:$Addr": {
|
|
"Desc": ["Does a memory load to a single element of a vector.",
|
|
"Leaves the rest of the vector's data intact.",
|
|
"Matches arm64 ld1 semantics"],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"VStoreVectorElement u8:#RegisterSize, u8:#ElementSize, FPR:$Value, u8:$Index, GPR:$Addr": {
|
|
"Desc": ["Does a memory store of a single element of a vector.",
|
|
"Matches arm64 st1 semantics"],
|
|
"HasSideEffects": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VBroadcastFromMem u8:#RegisterSize, u8:#ElementSize, GPR:$Address": {
|
|
"Desc": ["Broadcasts an ElementSize value from memory into each element of a vector."],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"GPR = Push u8:#Size, u8:$ValueSize, GPR:$Value, GPR:$Addr": {
|
|
"Desc": [
|
|
"Pushes a value to the address, returning the new pointer after incrementing.",
|
|
"The address is decremented by the value size while.",
|
|
"The return value size is the size of the current operating mode"
|
|
],
|
|
"HasSideEffects": true,
|
|
"DestSize": "Size"
|
|
},
|
|
"GPR = MemSet i1:$IsAtomic, u8:$Size, GPR:$Prefix, GPR:$Addr, GPR:$Value, GPR:$Length, GPR:$Direction": {
|
|
"Desc": ["Duplicates behaviour of x86 STOS repeat",
|
|
"Returns the final address that gets generated without the prefix appended."
|
|
],
|
|
"HasSideEffects": true,
|
|
"DestSize": "8"
|
|
},
|
|
"GPRPair = MemCpy i1:$IsAtomic, u8:$Size, GPR:$PrefixDest, GPR:$PrefixSrc, GPR:$AddrDest, GPR:$AddrSrc, GPR:$Length, GPR:$Direction": {
|
|
"Desc": ["Duplicates behaviour of x86 MOVS repeat",
|
|
"Returns the final addresses of destination and src addresses after they have been incremented or decremented"
|
|
],
|
|
"HasSideEffects": true,
|
|
"DestSize": "16",
|
|
"NumElements": "2"
|
|
},
|
|
"CacheLineClear GPR:$Addr, i1:$Serialize": {
|
|
"Desc": ["Does a 64 byte cacheline clear at the address specified",
|
|
"Only clears the data cachelines. Doesn't do any zeroing",
|
|
"Can skip serialization if requested."
|
|
],
|
|
"HasSideEffects": true
|
|
},
|
|
"CacheLineClean GPR:$Addr": {
|
|
"Desc": ["Does a 64 byte cacheline cleanat the address specified",
|
|
"Only cleans the data cachelines. Doesn't do any zeroing",
|
|
"Skips the invalidation step of the CacheLineClear operation"
|
|
],
|
|
"HasSideEffects": true
|
|
},
|
|
"CacheLineZero GPR:$Addr": {
|
|
"Desc": ["Does a 64 byte zero at the address specified",
|
|
"Writing zeroes to memory",
|
|
"It is specifically non-temporal and weakly ordered",
|
|
"This matches CLZero behaviour"
|
|
],
|
|
"HasSideEffects": true
|
|
},
|
|
"Fence FenceType:$Fence": {
|
|
"Desc": ["Does a memory fence operation of the desired type",
|
|
"Fence_Load: Ensures load memory operations are serialized",
|
|
"Fence_Store: Ensures store memory operations are serialized",
|
|
"Fence_LoadStore: Ensures loads and store memory operations are serialized",
|
|
"Ensures the memory operations are globally visible"
|
|
],
|
|
"HasSideEffects": true
|
|
}
|
|
},
|
|
"Atomic": {
|
|
"GPR = CAS OpSize:#Size, GPR:$Expected, GPR:$Desired, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Does a compare and swap of values to a memory location",
|
|
"This mostly matches the C++ atomic_compare_exchange_strong function",
|
|
"Dest = atomic_compare_exchange_strong(%Addr, %Expected, %Desired)",
|
|
"Depending on if the value in %Addr is Expected the results destination will be different",
|
|
"Behaves like the following but atomically",
|
|
"Dest = %Expected",
|
|
"if (deref(%Addr) != %Expected) Dest = deref(%Addr)"
|
|
],
|
|
|
|
"DestSize": "Size",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPRPair = CASPair OpSize:#Size, GPRPair:$Expected, GPRPair:$Desired, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Does a compare and exchange with two GPRPair values",
|
|
"ssa0 is the comparison value",
|
|
"ssa1 is the new value",
|
|
"ssa2 is the memory location",
|
|
"Returns a pair containing the value in memory"
|
|
],
|
|
"HasDest": true,
|
|
"DestSize": "Size",
|
|
"ImplicitFlagClobber": true,
|
|
"NumElements": "2",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i64Bit || Size == FEXCore::IR::OpSize::i128Bit"
|
|
]
|
|
},
|
|
"AtomicAdd OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer add"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"AtomicSub OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer sub"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"AtomicAnd OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer and"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"AtomicOr OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer or"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"AtomicXor OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer xor"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicSwap OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer swap"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicFetchAdd OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer fetch and add",
|
|
"Atomically fetches %Addr and adds %value to the memory location",
|
|
"Dest is the value prior to operating on the value in memory"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicFetchSub OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer fetch and sub",
|
|
"Atomically fetches %Addr and subtracts %value to the memory location",
|
|
"Dest is the value prior to operating on the value in memory"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicFetchAnd OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer fetch and binary and",
|
|
"Atomically fetches %Addr and binary ands %value to the memory location",
|
|
"Dest is the value prior to operating on the value in memory"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicFetchCLR OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer fetch and binary clear",
|
|
"Atomically fetches %Addr and binary clears %value to the memory location",
|
|
"Dest is the value prior to operating on the value in memory",
|
|
"Matches ARM ldclral semantics",
|
|
"eg: Dest[Addr] &= ~Value"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicFetchOr OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer fetch and binary or",
|
|
"Atomically fetches %Addr and binary ors %value to the memory location",
|
|
"Dest is the value prior to operating on the value in memory"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicFetchXor OpSize:#Size, GPR:$Value, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer fetch and binary exclusive or",
|
|
"Atomically fetches %Addr and binary exclusive ors %value to the memory location",
|
|
"Dest is the value prior to operating on the value in memory"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AtomicFetchNeg OpSize:#Size, GPR:$Addr": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Atomic integer fetch and two's complement negate",
|
|
"Dest is the value prior to operating on the value in memory"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"TelemetrySetValue GPR:$Value, u8:$TelemetryValueIndex": {
|
|
"HasSideEffects": true,
|
|
"Desc": ["Set Telemetry value if the passed in 32-bit value isn't zero.",
|
|
"Only useful for 32-bit applications."
|
|
],
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "8"
|
|
}
|
|
},
|
|
"ALU": {
|
|
"GPR = EntrypointOffset OpSize:#Size, i64:$Offset": {
|
|
"Desc": ["Returns the <entrypoint> + Offset address",
|
|
"When the size is 4 bytes then 32-bit overflow and underflow needs to work"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
|
|
"InlineEntrypointOffset OpSize:#Size, i64:$Offset": {
|
|
"Desc": ["Returns the <entrypoint> + Offset address",
|
|
"When the size is 4 bytes then 32-bit overflow and underflow needs to work"
|
|
],
|
|
"HasSideEffects": true,
|
|
"RAOverride": "0",
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
|
|
"GPR = Constant i64:$Constant": {
|
|
"Desc": ["Generates a 64bit constant inside of a GPR",
|
|
"Unsupported to create a constant in FPR"
|
|
],
|
|
"DestSize": "8"
|
|
},
|
|
|
|
"InlineConstant i64:$Constant": {
|
|
"Desc": ["Generates a 64bit constant to be used directly, non-FPR"],
|
|
"HasSideEffects": true,
|
|
"RAOverride": "0",
|
|
"DestSize": "8"
|
|
},
|
|
|
|
"GPRPair = TruncElementPair GPRPair:$Pair, u8:#ByteSize": {
|
|
"Desc": [
|
|
"Truncates each element of a pair to the destination size",
|
|
"TODO: This IR op should get removed"
|
|
],
|
|
"DestSize": "ByteSize * 2",
|
|
"NumElements": "2"
|
|
},
|
|
"GPR = CycleCounter": {
|
|
"Desc": ["Returns the host 64bit cycle counter",
|
|
"Useful when emulating rdtsc",
|
|
"Be careful, the frequency of this counter changes based on host",
|
|
"On AArch64 make sure to query the CNTFRQ_EL0 system register to get the frequency",
|
|
"On x86-64 make sure to query CPUID fn8000_0008[EDX_8] for constant TSC",
|
|
"x86-64 constant frequency lives in MSR_PLATFORM_INFO. Which is only available to kernel",
|
|
"Part of the ART frequency equation can be pulled from CPUID fn0000_0015[EBX & EAX]",
|
|
"But it's missing the ART multiplier still?"
|
|
],
|
|
"DestSize": "8"
|
|
},
|
|
|
|
"GPR = Neg OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Integer negation",
|
|
"Dest = -Src",
|
|
"Will truncate to 64 or 32bits"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Abs OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Integer 2's complement absolute value",
|
|
"Dest = std::abs(Src)",
|
|
"Will truncate to 64 or 32bits"
|
|
],
|
|
"DestSize": "Size",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Not OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Integer binary not",
|
|
"op:",
|
|
"Dest = ~Src"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Popcount OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Population count of source register",
|
|
"Returns the number of bits set"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = FindLSB OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Find least-significant-bit set",
|
|
"Returns the index of the least significant bit set",
|
|
"In the case of zero returns ~0U"
|
|
],
|
|
"DestSize": "Size",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = FindMSB OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Find most-significant-bit set",
|
|
"Returns the index of the most significant bit set",
|
|
"In the case of zero returns ~0U"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = FindTrailingZeroes OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Counts the number of trailing zero bits in a GPR",
|
|
"Returns the number of bits that are zero trailing",
|
|
"In the case of zero returns the size in bits of the input"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = CountLeadingZeroes OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Counts the number of leading zero bits in a GPR",
|
|
"Returns the number of bits that are zero leading",
|
|
"In the case of zero returns the size in bits of the input"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Rev OpSize:#Size, GPR:$Src": {
|
|
"Desc": ["Reverses the byte order of the register",
|
|
"Specifically 8bit byte swap size. (Not 16bit or 32bit word swapping)"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Add OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": [ "Integer Add",
|
|
"Will truncate to 64 or 32bits"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AddNZCV OpSize:$Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Return NZCV for the sum of two GPRs"],
|
|
"DestSize": "4",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"_Size == FEXCore::IR::OpSize::i32Bit || _Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = AdcNZCV OpSize:$Size, GPR:$Src1, GPR:$Src2, GPR:$NZCV": {
|
|
"Desc": ["Return NZCV for the sum of two GPRs and carry-in given as NZCV"],
|
|
"DestSize": "4",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"_Size == FEXCore::IR::OpSize::i32Bit || _Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = SbbNZCV OpSize:$Size, GPR:$Src1, GPR:$Src2, GPR:$NZCV": {
|
|
"Desc": ["Return NZCV for the sum of two GPRs and carry-in given as NZCV"],
|
|
"DestSize": "4",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"_Size == FEXCore::IR::OpSize::i32Bit || _Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Sub OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": [ "Integer Sub",
|
|
"Will truncate to 64 or 32bits"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = SubNZCV OpSize:$Size, GPR:$Src1, GPR:$Src2, u8:$InvertCarry": {
|
|
"Desc": ["Return NZCV for the difference of two GPRs. ",
|
|
"If InvertCarry is nonzero, carry flag uses x86 definition, inverted from arm64.",
|
|
""],
|
|
"DestSize": "4",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"_Size == FEXCore::IR::OpSize::i32Bit || _Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Or OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer binary or"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Orlshl OpSize:#Size, GPR:$Src1, GPR:$Src2, u8:$BitShift": {
|
|
"Desc": ["Integer binary or with logical shift left"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Orlshr OpSize:#Size, GPR:$Src1, GPR:$Src2, u8:$BitShift": {
|
|
"Desc": ["Integer binary or with logical shift right"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Ornror OpSize:#Size, GPR:$Src1, GPR:$Src2, u8:$BitShift": {
|
|
"Desc": ["Integer binary or with NOT on second source and rotation right"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Xor OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer binary exclusive or"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = And OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer binary and"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Andn OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer binary AND NOT. Performs the equivalent of Src1 & ~Src2"],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = TestNZ u8:$Size, GPR:$Src1": {
|
|
"Desc": ["Return NZCV for a GPR, setting N and Z accordingly and zeroing C and V"],
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "4"
|
|
},
|
|
"GPR = Lshl OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer logical shift left"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Lshr OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer logical shift right"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Ashr OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer arithmetic shift right"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Ror OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer rotate right"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Mul OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer signed multiplication"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = UMul OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer unsigned multiplication"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Div OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer signed division"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = UDiv OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer unsigned division"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Rem OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer signed remainder"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = URem OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer unsigned remainder"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = MulH OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer signed multiply returning high results",
|
|
"op:",
|
|
"Tmp <size * 2> = Src1 * Src2;",
|
|
"Dest = Tmp >> (size * 8);"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = UMulH OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
|
"Desc": ["Integer unsigned multiply returning high results",
|
|
"op:",
|
|
"Tmp <size * 2> = Src1 * Src2;",
|
|
"Dest = Tmp >> (size * 8);"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Bfi OpSize:#Size, u8:$Width, u8:$lsb, GPR:$Dest, GPR:$Src": {
|
|
"Desc": ["Copies a bitfield from one GPR to another",
|
|
"The source bitfield is from Src[Width:0]",
|
|
"The bitfield is copied in to Dest[(Width + lsb):lsb]"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Bfxil OpSize:#Size, u8:$Width, u8:$lsb, GPR:$Dest, GPR:$Src": {
|
|
"Desc": ["Copies a bitfield from one GPR to another",
|
|
"Inserting in to the low bits of the destination",
|
|
"The source bitfield is from Src[(Width + lsb):lsb]",
|
|
"The bitfield is copied in to Dest[Width:0]"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Bfe OpSize:#Size, u8:$Width, u8:$lsb, GPR:$Src": {
|
|
"Desc": ["Extracts a bitfield from one GPR with zext",
|
|
"The source bitfield is from Src[Width:0]",
|
|
"The bitfield is then zero extended"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Sbfe OpSize:#Size, u8:$Width, u8:$lsb, GPR:$Src": {
|
|
"Desc": ["Extracts a bitfield from one GPR with sext",
|
|
"The source bitfield is from Src[Width:0]",
|
|
"The bitfield is then sign extended"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = Select OpSize:#ResultSize, OpSize:$CompareSize, CondClass:$Cond, SSA:$Cmp1, SSA:$Cmp2, GPR:$TrueVal, GPR:$FalseVal": {
|
|
"Desc": ["Ternary selection of GPRs",
|
|
"op:",
|
|
"Dest = Cmp1 <Cond> Cmp2 ? TrueVal : FalseVal"
|
|
],
|
|
"DestSize": "ResultSize",
|
|
"ImplicitFlagClobber": true,
|
|
"EmitValidation": [
|
|
"_CompareSize == FEXCore::IR::OpSize::i32Bit || _CompareSize == FEXCore::IR::OpSize::i64Bit || _CompareSize == FEXCore::IR::OpSize::i128Bit",
|
|
"ResultSize == FEXCore::IR::OpSize::i32Bit || ResultSize == FEXCore::IR::OpSize::i64Bit",
|
|
"WalkFindRegClass($Cmp1) == WalkFindRegClass($Cmp2)"
|
|
]
|
|
},
|
|
"GPR = Extr OpSize:#Size, GPR:$Upper, GPR:$Lower, u8:$LSB": {
|
|
"Desc": ["Concats the two GPRs to create a value that is the size of the full two GPRs",
|
|
"It then extracts a bitfield width that size of a GPR from the LSB",
|
|
"Valid LSB range is 0-31 for 32bit and 0-63 for 64bit",
|
|
"<Size * 2> ConcatValue = $Upper:$Lower",
|
|
"Result = ConcatValue<LSB+Size - 1: LSB>"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = PDep OpSize:#Size, GPR:$Input, GPR:$Mask": {
|
|
"Desc": ["Performs a parallel bit deposit.",
|
|
"Takes the contiguous low-order bits and deposits them into",
|
|
"the destination at the locations specified by the Mask."
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
|
|
"GPR = PExt OpSize:#Size, GPR:$Input, GPR:$Mask": {
|
|
"Desc": ["Performs a parallel bit extract.",
|
|
"Each bit set in the mask will select the corresponding bit in the Input",
|
|
"and transfers them to the lower contiguous bits in the destination."
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
|
|
"GPR = LDiv OpSize:#Size, GPR:$Lower, GPR:$Upper, GPR:$Divisor": {
|
|
"Desc": ["Integer long unsigned division returning lower bits",
|
|
"The Lower and Upper registers will be concated together to generate a dividend twice the size",
|
|
"Then the divisor divides the temporary dividend and returns the results in the original sized register"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = LUDiv OpSize:#Size, GPR:$Lower, GPR:$Upper, GPR:$Divisor": {
|
|
"Desc": ["Integer long unsigned division returning lower bits",
|
|
"The Lower and Upper registers will be concated together to generate a dividend twice the size",
|
|
"Then the divisor divides the temporary dividend and returns the results in the original sized register"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = LRem OpSize:#Size, GPR:$Lower, GPR:$Upper, GPR:$Divisor": {
|
|
"Desc": ["Integer long signed remainder returning lower bits",
|
|
"The Lower and Upper registers will be concated together to generate a dividend twice the size",
|
|
"Then the divisor divides the temporary dividend and returns the remainder results in the original sized register"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
"GPR = LURem OpSize:#Size, GPR:$Lower, GPR:$Upper, GPR:$Divisor": {
|
|
"Desc": ["Integer long unsigned remainder returning lower bits",
|
|
"The Lower and Upper registers will be concated together to generate a dividend twice the size",
|
|
"Then the divisor divides the temporary dividend and returns the remainder results in the original sized register"
|
|
],
|
|
"DestSize": "Size",
|
|
"EmitValidation": [
|
|
"Size == FEXCore::IR::OpSize::i16Bit || Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
|
]
|
|
},
|
|
|
|
"Float to GPR": {"Ignore": 1},
|
|
"GPR = VExtractToGPR u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$Index": {
|
|
"Desc": ["Extracts an element from a vector and places it in a GPR",
|
|
"The element that is extracted from the vector is zero extended to the GPR size"
|
|
],
|
|
"DestSize": "ElementSize"
|
|
},
|
|
|
|
"GPR = Float_ToGPR_S u8:#DestElementSize, u8:$SrcElementSize, FPR:$Scalar": {
|
|
"Desc": ["Moves the scalar element to a GPR with conversion",
|
|
"Converts the 32bit or 64bit float to an signed integer",
|
|
"Rounding mode determined by host flag's rounding mode"
|
|
],
|
|
"DestSize": "DestElementSize"
|
|
},
|
|
|
|
"GPR = Float_ToGPR_ZS u8:#DestElementSize, u8:$SrcElementSize, FPR:$Scalar": {
|
|
"Desc": ["Moves the scalar element to a GPR with conversion",
|
|
"Converts the 32bit or 64bit float to an signed integer rounding towards zero (Truncating)"
|
|
],
|
|
"DestSize": "DestElementSize"
|
|
},
|
|
|
|
"GPR = FCmp u8:$ElementSize, FPR:$Scalar1, FPR:$Scalar2, u32:$Flags": {
|
|
"Desc": ["Does a scalar unordered compare and stores the asked for flags in to a GPR",
|
|
"Ordering flag result is true if either float input is NaN"
|
|
],
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "4"
|
|
}
|
|
},
|
|
"VectorScalar": {
|
|
"FPR = VFAddScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'add' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFSubScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'sub' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFMulScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'mul' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFDivScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'div' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFMinScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'min' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics.",
|
|
"Additionally matches x86 zero and NaN semantics",
|
|
"If both source operands are zero, return the second operand (in the case of negative and positive zero)",
|
|
"If either source operand is NaN then return the second operand."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFMaxScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'max' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics.",
|
|
"Additionally matches x86 zero and NaN semantics",
|
|
"If both source operands are zero, return the second operand (in the case of negative and positive zero)",
|
|
"If either source operand is NaN then return the second operand."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFSqrtScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'sqrt' on Vector2, inserting in to Vector1 and storing in to the destination.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFRSqrtScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'rsqrt' on Vector2, inserting in to Vector1 and storing in to the destination.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFRecpScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'recip' on Vector2, inserting in to Vector1 and storing in to the destination.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFToFScalarInsert OpSize:#RegisterSize, u8:#DstElementSize, u8:$SrcElementSize, FPR:$Vector1, FPR:$Vector2, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'cvt' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / DstElementSize"
|
|
},
|
|
"FPR = VSToFVectorInsert OpSize:#RegisterSize, u8:#DstElementSize, u8:$SrcElementSize, FPR:$Vector1, FPR:$Vector2, i8:$HasTwoElements, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a Vector 'scvt' between Vector1 and Vector2.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics.",
|
|
"HasTwoElements is slightly different than most of these scalar operations.",
|
|
"Handles the edge case of cvtpi2ps xmm0, mm0 which is two elements in the lower 64-bits"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / DstElementSize"
|
|
},
|
|
"FPR = VSToFGPRInsert OpSize:#RegisterSize, u8:#DstElementSize, u8:$SrcElementSize, FPR:$Vector, GPR:$Src, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'cvt' between Vector1 and GPR.",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / DstElementSize"
|
|
},
|
|
"FPR = VFToIScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, RoundType:$Round, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar round float to integral on Vector2, inserting in to Vector1 and storing in to the destination.",
|
|
"Rounding mode determined by argument",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPScalarInsert OpSize:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, FloatCompareOp:$Op, i1:$ZeroUpperBits": {
|
|
"Desc": ["Does a scalar 'cmp' between Vector1 and Vecto2, inserting in to Vector1 and storing in to the destination.",
|
|
"Compare op determined by argument",
|
|
"Inserting the result in to the lower element of Vector1 and returning the results.",
|
|
"If ZeroUpperBits is set then in a 256-bit wide operation it will zero the upper 128-bits of the destination.",
|
|
"For 128-bit operation this matches SSE insert semantics.",
|
|
"For 256-bit operation with ZeroUpperBits, this matches AVX insert semantics."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
}
|
|
},
|
|
"Vector": {
|
|
"FPR = VMov u8:#RegisterSize, FPR:$Source": {
|
|
"Desc" : ["Copy vector register",
|
|
"When Register size is smaller than Source register size,",
|
|
"this op is defined to truncate and zero extend"
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
|
|
"FPR = VectorZero u8:#RegisterSize": {
|
|
"Desc": ["Generates a vector zero",
|
|
"Useful to generate a zero vector without any previous dependencies"
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
|
|
"FPR = VectorImm u8:#RegisterSize, u8:#ElementSize, u8:$Immediate": {
|
|
"Desc": ["Generates a vector with each element containg the immediate zexted"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = LoadNamedVectorConstant u8:#RegisterSize, NamedVectorConstant:$Constant": {
|
|
"Desc": ["Load a named vector constant.",
|
|
"The list of vector constants can be found in <FEXCore/IR/IR.h>"
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = LoadNamedVectorIndexedConstant u8:#RegisterSize, IndexNamedVectorConstant:$Constant, u32:$Index": {
|
|
"Desc": ["Load a named vector constant from Indexable table.",
|
|
"Index needs to be aligned register size.",
|
|
"The list of indexable vector constants can be found in <FEXCore/IR/IR.h>"
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = VNeg u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VNot u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VAbs u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Does an signed integer absolute"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VPopcount u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Does a popcount for each element of the register"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VAddV u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Does a horizontal vector add of elements across the source vector",
|
|
"Result is a zero extended scalar"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUMinV u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Does a horizontal vector unsigned minimum of elements across the source vector",
|
|
"Result is a zero extended scalar"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VFAbs u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VFNeg u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VFRecp u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VFSqrt u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VFRSqrt u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VCMPEQZ u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VCMPGTZ u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Vector compare signed greater than",
|
|
"Each element is compared, if the result is true then the resulting element is ~0, else zero",
|
|
"Compares the vector against zero"
|
|
],
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VCMPLTZ u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Vector compare signed less than",
|
|
"Each element is compared, if the result is true then the resulting element is ~0, else zero",
|
|
"Compares the vector against zero"
|
|
],
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VDupElement u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$Index": {
|
|
"Desc": ["Duplicates one element from the source register across the whole register"],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VShlI u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$BitShift": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUShrI u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$BitShift": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSShrI u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$BitShift": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VUShrNI u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$BitShift": {
|
|
"Desc": "Unsigned shifts right each element and then narrows to the next lower element size",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
|
|
"FPR = VUShrNI2 u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper, u8:$BitShift": {
|
|
"Desc": ["Unsigned shifts right each element and then narrows to the next lower element size",
|
|
"Inserts results in to the high elements of the first argument"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
"FPR = VSXTL u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": "Sign extends elements from the source element size to the next size up",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VSXTL2 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Sign extends elements from the source element size to the next size up",
|
|
"Source elements come from the upper half of the register"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VUXTL u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": "Zero extends elements from the source element size to the next size up",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VUXTL2 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Zero extends elements from the source element size to the next size up",
|
|
"Source elements come from the upper half of the register"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VSQXTN u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
"FPR = VSQXTN2 u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
"FPR = VSQXTNPair u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"Desc": ["Does both VSQXTN and VSQXTN2 in a combined operation."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
"FPR = VSQXTUN u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
"FPR = VSQXTUN2 u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
"FPR = VSQXTUNPair u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"Desc": ["Does both VSQXTUN and VSQXTUN2 in a combined operation."
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize >> 1)"
|
|
},
|
|
"FPR = VSRSHR u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$BitShift": {
|
|
"Desc": ["Signed rounding shift right by immediate",
|
|
"Exactly matching Arm64 srshr semantics"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSQSHL u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, u8:$BitShift": {
|
|
"Desc": ["Signed satuating shift left by immediate",
|
|
"Exactly matching Arm64 sqshl semantics"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VRev32 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc" : ["Reverses elements in 32-bit halfwords",
|
|
"Available element size: 1byte, 2 byte"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VRev64 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc" : ["Reverses elements in 64-bit halfwords",
|
|
"Available element size: 1byte, 2 byte, 4 byte"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VAdd u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VSub u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VAnd u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VBic u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VOr u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VXor u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VUQAdd u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VUQSub u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VSQAdd u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VSQSub u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VAddP u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"Desc": "Does a horizontal pairwise add of elements across the two source vectors",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VURAvg u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": ["Does an unsigned rounded average", "dst_elem = (src1_elem + src2_elem + 1) >> 1"],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUMin u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUMax u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSMin u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSMax u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VZip u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VZip2 u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUnZip u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUnZip2 u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VTrn u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VTrn2 u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VFAdd u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFAddP u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper": {
|
|
"Desc": "Does a horizontal pairwise add of elements across the two source vectors with float element types",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFSub u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFMul u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFDiv u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VFMin u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFMax u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VMul u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUMull u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VSMull u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": [ "Does a signed integer multiply with extend.",
|
|
"ElementSize is the source size"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VUMull2 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": "Multiplies the high elements with size extension",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VSMull2 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": "Multiplies the high elements with size extension",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VUMulH u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": "Wide unsigned multiply returning the high results",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSMulH u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": "Wide signed multiply returning the high results",
|
|
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUABDL u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": ["Unsigned Absolute Difference Long"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VUABDL2 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": ["Unsigned Absolute Difference Long",
|
|
"Using the high elements of the source vectors"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / (ElementSize << 1)"
|
|
},
|
|
"FPR = VUShl u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftVector, i1:$RangeCheck": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUShr u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftVector, i1:$RangeCheck": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSShr u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftVector, i1:$RangeCheck": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUShlS u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftScalar": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUShrS u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftScalar": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSShrS u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftScalar": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUShrSWide u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftScalar": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSShrSWide u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftScalar": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUShlSWide u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, FPR:$ShiftScalar": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VInsElement u8:#RegisterSize, u8:#ElementSize, u8:$DestIdx, u8:$SrcIdx, FPR:$DestVector, FPR:$SrcVector": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VInsGPR u8:#RegisterSize, u8:#ElementSize, u8:$DestIdx, FPR:$DestVector, GPR:$Src": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VExtr u8:#RegisterSize, u8:#ElementSize, FPR:$VectorLower, FPR:$VectorUpper, u8:$Index": {
|
|
"Desc": ["Concats two vector registers together and extracts a full width register from the element index",
|
|
"Index is an element index. So it is offset by ElementSize argument",
|
|
"op:",
|
|
"TmpVector <RegisterSize *2> = concat(Upper:Lower)",
|
|
"Dest = TmpVector >> (ElementSize * Index * 8); // Or can be thought of `concat(&TmpVector[Index], i128)`"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VCMPEQ u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VCMPGT u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"Desc": ["Vector compare signed greater than",
|
|
"Each element is compared, if the result is true then the resulting element is ~0, else zero"
|
|
],
|
|
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPEQ u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"ImplicitFlagClobber": true,
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPNEQ u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPLT u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPGT u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPLE u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPORD u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPUNO u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VTBL1 u8:#RegisterSize, FPR:$VectorTable, FPR:$VectorIndices": {
|
|
"Desc": ["Does a vector table lookup from one register in to the destination",
|
|
"Lookup is byte sized per byte element.",
|
|
"Any index larger than what the registers provide will result in zero for that element",
|
|
"Table is always treated as a 128bit register",
|
|
"Indices matches destination size. Either 64bit or 128bit"
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = VTBL2 u8:#RegisterSize, FPR:$VectorTable1, FPR:$VectorTable2, FPR:$VectorIndices": {
|
|
"Desc": ["Does a vector table lookup from two registers in to the destination",
|
|
"Lookup is byte sized per byte element.",
|
|
"Any index larger than what the registers provide will result in zero for that element",
|
|
"Table is always treated as a two 128bit registers",
|
|
"Indices matches destination size. Either 64bit or 128bit",
|
|
"Careful about not using sequential table registers, will result in some moves if they aren't sequential."
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = VBSL u8:#RegisterSize, FPR:$VectorMask, FPR:$VectorTrue, FPR:$VectorFalse": {
|
|
"Desc": ["Does a vector bitwise select.",
|
|
"If the bit in the field is 1 then the corresponding bit is pulled from VectorTrue",
|
|
"If the bit in the field is 0 then the corresponding bit is pulled from VectorFalse"
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
|
|
"GPR = VPCMPESTRX FPR:$LHS, FPR:$RHS, GPR:$RAX, GPR:$RDX, u16:$Control": {
|
|
"Desc": ["Performs intermediate behavior analogous to the x86 PCMPESTRI/PCMPESTRM instruction",
|
|
"This will return the intermediate result of a PCMPESTR-type operation, but NOT the final",
|
|
"result. This must be derived from the intermediate result",
|
|
|
|
"NOTE: On top of returning the intermediate result, the returned value also combines the status",
|
|
"flags into the upper 16-bits of the 32-bit result, as these can also be derived over the",
|
|
"course of creating the intermediate result"
|
|
],
|
|
"DestSize": "4",
|
|
"JITDispatch": false
|
|
},
|
|
"GPR = VPCMPISTRX FPR:$LHS, FPR:$RHS, u8:$Control": {
|
|
"Desc": ["Performs intermediate behavior analogous to the x86 PCMPISTRI/PCMPISTRM instruction",
|
|
"This will return the intermediate result of a PCMPISTR-type operation, but NOT the final",
|
|
"result. This must be derived from the intermediate result",
|
|
|
|
"NOTE: On top of returning the intermediate result, the returned value also combines the status",
|
|
"flags into the upper 16-bits of the 32-bit result, as these can also be derived over the",
|
|
"course of creating the intermediate result"
|
|
],
|
|
"DestSize": "4",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = VFCADD u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2, u16:$Rotate": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
}
|
|
},
|
|
"Conv": {
|
|
"FPR = VCastFromGPR u8:#RegisterSize, u8:#ElementSize, GPR:$Src": {
|
|
"Desc": ["Moves a GPR to a Vector register with zero extension to full length of the register.",
|
|
"No conversion is done on the data as it moves register files"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = VDupFromGPR u8:#RegisterSize, u8:#ElementSize, GPR:$Src": {
|
|
"Desc": ["Broadcasts a value in a GPR into each ElementSize-sized element in a vector"],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
|
|
"FPR = Float_FromGPR_S u8:#DstElementSize, u8:$SrcElementSize, GPR:$Src": {
|
|
"Desc": ["Scalar op: Converts signed GPR to Scalar float",
|
|
"Zeroes the upper bits of the vector register"
|
|
],
|
|
"DestSize": "DstElementSize"
|
|
},
|
|
"FPR = Float_FToF u8:#DstElementSize, u8:$SrcElementSize, FPR:$Scalar": {
|
|
"Desc": ["Scalar op: Converts float from one size to another",
|
|
"Zeroes the upper bits of the vector register"
|
|
],
|
|
"DestSize": "DstElementSize"
|
|
},
|
|
|
|
"FPR = Vector_SToF u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": "Vector op: Converts signed integer to same size float",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = Vector_FToS u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": ["Vector op: Converts float to signed integer, rounding towards zero",
|
|
"Rounding mode determined by host rounding mode"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = Vector_FToZS u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
|
"Desc": "Vector op: Converts float to signed integer, rounding towards zero",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = Vector_FToF u8:#RegisterSize, u8:#DestElementSize, FPR:$Vector, u8:$SrcElementSize": {
|
|
"Desc": "Vector op: Converts float from source element size to destination size (fp32<->fp64)",
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / DestElementSize"
|
|
},
|
|
"FPR = Vector_FToI u8:#RegisterSize, u8:#ElementSize, FPR:$Vector, RoundType:$Round": {
|
|
"Desc": ["Vector op: Rounds float to integral",
|
|
"Rounding mode determined by argument"
|
|
],
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
}
|
|
},
|
|
"Crypto": {
|
|
"FPR = VAESImc FPR:$Vector": {
|
|
"Desc": "Does a stage of the inverse mix column transformation",
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = VAESEnc u8:#RegisterSize, FPR:$State, FPR:$Key, FPR:$ZeroReg": {
|
|
"Desc": "Does a step of AES encryption",
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = VAESEncLast u8:#RegisterSize, FPR:$State, FPR:$Key, FPR:$ZeroReg": {
|
|
"Desc": "Does the last step of AES encryption",
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = VAESDec u8:#RegisterSize, FPR:$State, FPR:$Key, FPR:$ZeroReg": {
|
|
"Desc": "Does a step of AES decryption",
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = VAESDecLast u8:#RegisterSize, FPR:$State, FPR:$Key, FPR:$ZeroReg": {
|
|
"Desc": "Does the last step of AES decryption",
|
|
"DestSize": "RegisterSize"
|
|
},
|
|
"FPR = VAESKeyGenAssist FPR:$Src, FPR:$KeyGenTBLSwizzle, FPR:$ZeroReg, u8:$RCON": {
|
|
"Desc": "Assists in key generation",
|
|
"DestSize": "16"
|
|
},
|
|
"GPR = CRC32 GPR:$Src1, GPR:$Src2, u8:$SrcSize": {
|
|
"Desc": ["CRC32 using polynomial 0x1EDC6F41"
|
|
],
|
|
"DestSize": "4"
|
|
},
|
|
"FPR = PCLMUL u8:#RegisterSize, FPR:$Src1, FPR:$Src2, u8:$Selector": {
|
|
"Desc": [
|
|
"Performs carryless multiplication of 64-bit elements depending on the selector.",
|
|
"Selector = 0b00000000: Uses low 64-bit elements from both input vectors",
|
|
"Selector = 0b00000001: Uses high 64-bit element from Src1 and low 64-bit element from Src2",
|
|
"Selector = 0b00010000: Uses low 64-bit element from Src1 and high 64-bit element from Src2",
|
|
"Selector = 0b00010001: Uses high 64-bit elements from both input vectors"
|
|
],
|
|
"DestSize": "RegisterSize"
|
|
}
|
|
},
|
|
"F64": {
|
|
"FPR = F64ATAN FPR:$Src1, FPR:$Src2": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64FPREM FPR:$Src1, FPR:$Src2": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64FPREM1 FPR:$Src1, FPR:$Src2": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64SCALE FPR:$Src1, FPR:$Src2": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64F2XM1 FPR:$Src": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64FYL2X FPR:$Src, FPR:$Src2": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64TAN FPR:$Src": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64SIN FPR:$Src": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F64COS FPR:$Src": {
|
|
"DestSize": "8",
|
|
"JITDispatch": false
|
|
}
|
|
},
|
|
"F80": {
|
|
"FPR = F80Add FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80Sub FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80Mul FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80Div FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80ATAN FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80FPREM FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80FPREM1 FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80SCALE FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80CVT u8:#Size, FPR:$X80Src": {
|
|
"DestSize": "Size",
|
|
"JITDispatch": false
|
|
},
|
|
"GPR = F80CVTInt u8:#Size, FPR:$X80Src, i1:$Truncate": {
|
|
"DestSize": "Size",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80CVTTo FPR:$X80Src, u8:$SrcSize": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80CVTToInt GPR:$Src, u8:$SrcSize": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80Round FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80F2XM1 FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80TAN FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80SIN FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80COS FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80SQRT FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80XTRACT_EXP FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80XTRACT_SIG FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"GPR = F80Cmp FPR:$X80Src1, FPR:$X80Src2, u32:$Flags": {
|
|
"Desc": ["Does a scalar unordered compare and stores the asked for flags in to a GPR",
|
|
"Ordering flag result is true if either float input is NaN"
|
|
],
|
|
"DestSize": "4",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80BCDLoad FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
"FPR = F80BCDStore FPR:$X80Src": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
},
|
|
|
|
"FPR = F80FYL2X FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16",
|
|
"JITDispatch": false
|
|
}
|
|
},
|
|
"Backend": {
|
|
"Last": {
|
|
"HasSideEffects": true
|
|
}
|
|
}
|
|
}
|
|
}
|