From d01b457727208fd34511d48e850e3b4a33d76147 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sat, 23 Sep 2023 03:19:52 -0700 Subject: [PATCH 1/3] RCLSE: Optimize redundant store->load operations The bug that was causing crashes with this was due to inline syscalls. Now that this is fixed we can re-enable store->load operations. This allows constant propagation to work significantly better, which means inline syscalls start working again. This can significantly improve syscall performance in some cases. This is most likely to improve performance in dxsetup and vc_redist but hard to get a real profile. Additionally this will let us inline cpuid results in the future which is pretty nice. --- .../IR/Passes/DeadContextStoreElimination.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index ff6123a2d..8b58ba555 100644 --- a/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -506,17 +506,17 @@ bool RCLSE::ClassifyContextLoad(FEXCore::IR::IREmitter *IREmit, ContextInfo *Loc ContextMemberInfo PreviousMemberInfoCopy = *Info; RecordAccess(Info, Class, Offset, Size, LastAccessType::READ, CodeNode); - if (IsReadAccess(PreviousMemberInfoCopy.Accessed) && - IsReadAccess(Info->Accessed) && - PreviousMemberInfoCopy.AccessRegClass == Info->AccessRegClass && + if (PreviousMemberInfoCopy.AccessRegClass == Info->AccessRegClass && PreviousMemberInfoCopy.AccessOffset == Info->AccessOffset && PreviousMemberInfoCopy.AccessSize == Size) { - // Optimize the case of redundant reads of the same exact value. + // This optimizes two cases: + // - Previous access was a load, and we have a redundant load of the same value. + // - Previous access was a store, and we are redundantly loading immediately after the store. Eliminating the store. IREmit->ReplaceAllUsesWithRange(CodeNode, PreviousMemberInfoCopy.ValueNode, IREmit->GetIterator(IREmit->WrapNode(CodeNode)), BlockEnd); RecordAccess(Info, Class, Offset, Size, LastAccessType::READ, PreviousMemberInfoCopy.ValueNode); return true; } - // TODO: Optimize the case of Store->Load. + // TODO: Optimize the case of partial loads. return false; } From 9ab2967d7192c0dd84d2842a451a7763e6cd50cc Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sat, 23 Sep 2023 03:35:11 -0700 Subject: [PATCH 2/3] Arm64: Fixes wide shifts movprfx is invalid to use when the source register matches the movprfx destination. This was getting picked up on by `TwoByte/0F_D1.asm` now that RCLSE is working better now. --- .../Interface/Core/JIT/Arm64/VectorOps.cpp | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp index 3ff3a6f9f..380f09217 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp @@ -2544,12 +2544,18 @@ DEF_OP(VUShrSWide) { else if (HostSupportsSVE128) { const auto Mask = PRED_TMP_16B.Merging(); - auto ShiftRegister = ShiftScalar.Z(); + auto ShiftRegister = ShiftScalar; if (OpSize > 8) { // SVE wide shifts don't need to duplicate the low bits unless the OpSize is 16-bytes // Slightly more optimal for 8-byte opsize. dup(ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), ShiftScalar.Z(), 0); - ShiftRegister = VTMP1.Z(); + ShiftRegister = VTMP1; + } + + if (Dst == ShiftRegister) { + // If destination aliases the shift vector then we need to move it temporarily. + mov(VTMP1.Z(), ShiftRegister.Z()); + ShiftRegister = VTMP1; } if (Dst != Vector) { @@ -2557,10 +2563,10 @@ DEF_OP(VUShrSWide) { movprfx(Dst.Z(), Vector.Z()); } if (ElementSize == 8) { - lsr(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister); + lsr(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } else { - lsr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister); + lsr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } } else { // uqshl + ushr of 57-bits leaves 7-bits remaining. @@ -2611,12 +2617,18 @@ DEF_OP(VSShrSWide) { else if (HostSupportsSVE128) { const auto Mask = PRED_TMP_16B.Merging(); - auto ShiftRegister = ShiftScalar.Z(); + auto ShiftRegister = ShiftScalar; if (OpSize > 8) { // SVE wide shifts don't need to duplicate the low bits unless the OpSize is 16-bytes // Slightly more optimal for 8-byte opsize. dup(ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), ShiftScalar.Z(), 0); - ShiftRegister = VTMP1.Z(); + ShiftRegister = VTMP1; + } + + if (Dst == ShiftRegister) { + // If destination aliases the shift vector then we need to move it temporarily. + mov(VTMP1.Z(), ShiftRegister.Z()); + ShiftRegister = VTMP1; } if (Dst != Vector) { @@ -2624,10 +2636,10 @@ DEF_OP(VSShrSWide) { movprfx(Dst.Z(), Vector.Z()); } if (ElementSize == 8) { - asr(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister); + asr(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } else { - asr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister); + asr_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } } else { // uqshl + ushr of 57-bits leaves 7-bits remaining. @@ -2678,12 +2690,18 @@ DEF_OP(VUShlSWide) { else if (HostSupportsSVE128) { const auto Mask = PRED_TMP_16B.Merging(); - auto ShiftRegister = ShiftScalar.Z(); + auto ShiftRegister = ShiftScalar; if (OpSize > 8) { // SVE wide shifts don't need to duplicate the low bits unless the OpSize is 16-bytes // Slightly more optimal for 8-byte opsize. dup(ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), ShiftScalar.Z(), 0); - ShiftRegister = VTMP1.Z(); + ShiftRegister = VTMP1; + } + + if (Dst == ShiftRegister) { + // If destination aliases the shift vector then we need to move it temporarily. + mov(VTMP1.Z(), ShiftRegister.Z()); + ShiftRegister = VTMP1; } if (Dst != Vector) { @@ -2691,10 +2709,10 @@ DEF_OP(VUShlSWide) { movprfx(Dst.Z(), Vector.Z()); } if (ElementSize == 8) { - lsl(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister); + lsl(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } else { - lsl_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister); + lsl_wide(SubRegSize, Dst.Z(), Mask, Dst.Z(), ShiftRegister.Z()); } } else { // uqshl + ushr of 57-bits leaves 7-bits remaining. From be3ff804a6843dfbdfca66106447eccc755b430b Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sat, 23 Sep 2023 06:11:35 -0700 Subject: [PATCH 3/3] InstCountCI: Update for optimization --- unittests/InstructionCountCI/x87.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/unittests/InstructionCountCI/x87.json b/unittests/InstructionCountCI/x87.json index 97f6808a5..a66f402ac 100644 --- a/unittests/InstructionCountCI/x87.json +++ b/unittests/InstructionCountCI/x87.json @@ -9039,7 +9039,7 @@ ] }, "fucompp": { - "ExpectedInstructionCount": 77, + "ExpectedInstructionCount": 76, "Optimal": "No", "Comment": [ "0xda 11b 0xe9 /5" @@ -9115,7 +9115,6 @@ "strb w22, [x28, #1010]", "add w20, w20, #0x1 (1)", "and w20, w20, #0x7", - "ldrb w22, [x28, #1010]", "lsl w21, w21, w20", "bic w21, w22, w21", "strb w21, [x28, #1010]", @@ -19655,7 +19654,7 @@ ] }, "fcompp": { - "ExpectedInstructionCount": 77, + "ExpectedInstructionCount": 76, "Optimal": "No", "Comment": [ "0xde 11b 0xd9 /3" @@ -19731,7 +19730,6 @@ "strb w22, [x28, #1010]", "add w20, w20, #0x1 (1)", "and w20, w20, #0x7", - "ldrb w22, [x28, #1010]", "lsl w21, w21, w20", "bic w21, w22, w21", "strb w21, [x28, #1010]",