diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp index 5141cf2f7..443a92608 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/ALUOps.cpp @@ -187,6 +187,16 @@ DEF_OP(Sub) { } } +DEF_OP(SubShift) { + auto Op = IROp->C(); + const uint8_t OpSize = IROp->Size; + + LOGMAN_THROW_AA_FMT(OpSize == 4 || OpSize == 8, "Unsupported {} size: {}", __func__, OpSize); + const auto EmitSize = OpSize == 8 ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit; + + sub(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()), ConvertIRShiftType(Op->Shift), Op->ShiftAmount); +} + DEF_OP(SubNZCV) { auto Op = IROp->C(); const IR::OpSize OpSize = Op->Size; diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h b/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h index 088210168..2926255f3 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/JITClass.h @@ -116,6 +116,15 @@ private: return PhyReg; } + // Converts IR-base shift type to ARMEmitter shift type. + // Will be a no-op, only a type conversion since the two definitions match. + [[nodiscard]] ARMEmitter::ShiftType ConvertIRShiftType(IR::ShiftType Shift) const { + return Shift == IR::ShiftType::LSL ? ARMEmitter::ShiftType::LSL : + Shift == IR::ShiftType::LSR ? ARMEmitter::ShiftType::LSR : + Shift == IR::ShiftType::ASR ? ARMEmitter::ShiftType::ASR : + ARMEmitter::ShiftType::ROR; + } + [[nodiscard]] bool IsFPR(IR::NodeID Node) const; [[nodiscard]] bool IsGPR(IR::NodeID Node) const; [[nodiscard]] bool IsGPRPair(IR::NodeID Node) const; diff --git a/FEXCore/Source/Interface/IR/IR.json b/FEXCore/Source/Interface/IR/IR.json index 1ce60b909..3c2361f70 100644 --- a/FEXCore/Source/Interface/IR/IR.json +++ b/FEXCore/Source/Interface/IR/IR.json @@ -158,7 +158,8 @@ "RoundType": "RoundType", "FloatCompareOp": "FloatCompareOp", "NamedVectorConstant": "FEXCore::IR::NamedVectorConstant", - "IndexNamedVectorConstant": "FEXCore::IR::IndexNamedVectorConstant" + "IndexNamedVectorConstant": "FEXCore::IR::IndexNamedVectorConstant", + "ShiftType": "FEXCore::IR::ShiftType" }, "Ops": { "Misc": { @@ -953,6 +954,16 @@ "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit" ] }, + "GPR = SubShift OpSize:#Size, GPR:$Src1, GPR:$Src2, ShiftType:$Shift{ShiftType::LSL}, u8:$ShiftAmount{0}": { + "Desc": [ "Integer Sub with shifted register", + "Will truncate to 64 or 32bits" + ], + "DestSize": "Size", + "EmitValidation": [ + "Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit", + "_Shift != ShiftType::ROR" + ] + }, "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.", diff --git a/FEXCore/Source/Interface/IR/IRDumper.cpp b/FEXCore/Source/Interface/IR/IRDumper.cpp index 68cd2497b..dedaf3c1a 100644 --- a/FEXCore/Source/Interface/IR/IRDumper.cpp +++ b/FEXCore/Source/Interface/IR/IRDumper.cpp @@ -257,6 +257,16 @@ static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const *out << static_cast(Arg.si_code) << "}"; } +static void PrintArg(fextl::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::ShiftType Arg) { + switch (Arg) { + case ShiftType::LSL: *out << "LSL"; break; + case ShiftType::LSR: *out << "LSR"; break; + case ShiftType::ASR: *out << "ASR"; break; + case ShiftType::ROR: *out << "ROR"; break; + default: *out << ""; break; + } +} + void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData) { auto HeaderOp = IR->GetHeader(); diff --git a/FEXCore/include/FEXCore/IR/IR.h b/FEXCore/include/FEXCore/IR/IR.h index 5c130e31c..6d1c25daf 100644 --- a/FEXCore/include/FEXCore/IR/IR.h +++ b/FEXCore/include/FEXCore/IR/IR.h @@ -564,6 +564,13 @@ enum class FloatCompareOp : uint8_t { ORD, }; +enum class ShiftType : uint8_t { + LSL = 0, + LSR, + ASR, + ROR, +}; + // Converts a size stored as an integer in to an OpSize enum. // This is a nop operation and will be eliminated by the compiler. static inline OpSize SizeToOpSize(uint8_t Size) {