mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 10:00:16 +02:00
Changes the helper which all the source uses to still calculate the size implicitly. This is going to take a while to convert all implicit uses over to the explicit operation. Get us started by at least having the IR operation itself be explicit.
1992 lines
86 KiB
JSON
1992 lines
86 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_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",
|
|
"NamedVectorConstant": "FEXCore::IR::NamedVectorConstant",
|
|
"IndexNamedVectorConstant": "FEXCore::IR::IndexNamedVectorConstant"
|
|
},
|
|
"Ops": {
|
|
"Misc": {
|
|
"Dummy": {
|
|
"HasSideEffects": true,
|
|
"SwitchGen": false
|
|
},
|
|
"IRHeader SSA:$Blocks, u64:$OriginalRIP, u32:$BlockCount, u32:$NumHostInstructions": {
|
|
"SwitchGen": false
|
|
},
|
|
"CodeBlock SSA:$Begin, SSA:$Last": {
|
|
"SwitchGen": false,
|
|
"RAOverride": "0"
|
|
},
|
|
"BeginBlock SSA:$BlockHeader": {
|
|
"HasSideEffects": true,
|
|
"SwitchGen": false,
|
|
"RAOverride": "0"
|
|
},
|
|
"InvalidateFlags u64:$Flags": {
|
|
"HasSideEffects": true
|
|
},
|
|
|
|
"EndBlock SSA:$BlockHeader": {
|
|
"HasSideEffects": true,
|
|
"SwitchGen": false,
|
|
"RAOverride": "0"
|
|
},
|
|
|
|
"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,
|
|
"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"
|
|
],
|
|
"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"
|
|
},
|
|
|
|
"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",
|
|
"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"
|
|
},
|
|
|
|
"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",
|
|
"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"],
|
|
"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,
|
|
"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",
|
|
"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",
|
|
"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 = 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."
|
|
],
|
|
"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",
|
|
"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",
|
|
"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",
|
|
"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": {
|
|
"Desc": ["Return NZCV for the difference of two GPRs. ",
|
|
"Note: Carry flag uses x86 definition, inverted from arm64.",
|
|
""],
|
|
"DestSize": "4",
|
|
"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 = 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"],
|
|
"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 = 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",
|
|
"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"
|
|
],
|
|
"DestSize": "4"
|
|
}
|
|
},
|
|
"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 = 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": {
|
|
"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"
|
|
],
|
|
"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"
|
|
],
|
|
"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": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFMax u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VUMul u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VSMul 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"
|
|
],
|
|
|
|
"DestSize": "RegisterSize",
|
|
"NumElements": "RegisterSize / ElementSize"
|
|
},
|
|
"FPR = VFCMPEQ u8:#RegisterSize, u8:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
|
"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"
|
|
},
|
|
"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"
|
|
},
|
|
"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"
|
|
},
|
|
"FPR = F64FPREM FPR:$Src1, FPR:$Src2": {
|
|
"DestSize": "8"
|
|
},
|
|
"FPR = F64FPREM1 FPR:$Src1, FPR:$Src2": {
|
|
"DestSize": "8"
|
|
},
|
|
"FPR = F64SCALE FPR:$Src1, FPR:$Src2": {
|
|
"DestSize": "8"
|
|
},
|
|
"FPR = F64F2XM1 FPR:$Src": {
|
|
"DestSize": "8"
|
|
},
|
|
"FPR = F64FYL2X FPR:$Src, FPR:$Src2": {
|
|
"DestSize": "8"
|
|
},
|
|
"FPR = F64TAN FPR:$Src": {
|
|
"DestSize": "8"
|
|
},
|
|
"FPR = F64SIN FPR:$Src": {
|
|
"DestSize": "8"
|
|
},
|
|
"FPR = F64COS FPR:$Src": {
|
|
"DestSize": "8"
|
|
}
|
|
},
|
|
"F80": {
|
|
"F80LoadFCW GPR:$Src": {
|
|
"HasSideEffects": true
|
|
},
|
|
"FPR = F80Add FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80Sub FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80Mul FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
|
|
"FPR = F80Div FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80ATAN FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80FPREM FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80FPREM1 FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80SCALE FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80CVT u8:#Size, FPR:$X80Src": {
|
|
"DestSize": "Size"
|
|
},
|
|
"GPR = F80CVTInt u8:#Size, FPR:$X80Src, i1:$Truncate": {
|
|
"DestSize": "Size"
|
|
},
|
|
"FPR = F80CVTTo FPR:$X80Src, u8:$SrcSize": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80CVTToInt GPR:$Src, u8:$SrcSize": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80Round FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80F2XM1 FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80TAN FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80SIN FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80COS FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80SQRT FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80XTRACT_EXP FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80XTRACT_SIG FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"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"
|
|
},
|
|
"FPR = F80BCDLoad FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
"FPR = F80BCDStore FPR:$X80Src": {
|
|
"DestSize": "16"
|
|
},
|
|
|
|
"FPR = F80FYL2X FPR:$X80Src1, FPR:$X80Src2": {
|
|
"DestSize": "16"
|
|
}
|
|
},
|
|
"Backend": {
|
|
"Last": {
|
|
"HasSideEffects": true
|
|
}
|
|
}
|
|
}
|
|
}
|