diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h index 5194f05e63..fdb569496c 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.h +++ b/rpcs3/Emu/CPU/CPUTranslator.h @@ -3790,8 +3790,81 @@ template return from_sve_vector(result, fixed_type); } - -template + + template + value_t sve_mull(llvm::Intrinsic::ID id, T1 a, T2 b) + { + value_t result; + + const auto fixed_type = llvm::cast(get_type()); + const auto scalable_type = llvm::ScalableVectorType::get(fixed_type->getElementType(), fixed_type->getNumElements()); + const auto data0 = to_sve_vector(a.eval(m_ir)); + const auto data1 = to_sve_vector(b.eval(m_ir)); + const std::array types{scalable_type}; + + result.value = from_sve_vector(m_ir->CreateIntrinsic(id, types, {data0, data1}), fixed_type); + return result; + } + + template + value_t sve_mlal(llvm::Intrinsic::ID id, T0 acc, T1 a, T2 b) + { + value_t result; + + const auto fixed_type = llvm::cast(get_type()); + const auto scalable_type = llvm::ScalableVectorType::get(fixed_type->getElementType(), fixed_type->getNumElements()); + const auto data0 = to_sve_vector(acc.eval(m_ir)); + const auto data1 = to_sve_vector(a.eval(m_ir)); + const auto data2 = to_sve_vector(b.eval(m_ir)); + const std::array types{scalable_type}; + + result.value = from_sve_vector(m_ir->CreateIntrinsic(id, types, {data0, data1, data2}), fixed_type); + return result; + } + + template + value_t sve_smullb(T1 a, T2 b) + { + return sve_mull(llvm::Intrinsic::aarch64_sve_smullb, a, b); + } + + template + value_t sve_smullt(T1 a, T2 b) + { + return sve_mull(llvm::Intrinsic::aarch64_sve_smullt, a, b); + } + + template + value_t sve_umullb(T1 a, T2 b) + { + return sve_mull(llvm::Intrinsic::aarch64_sve_umullb, a, b); + } + + template + value_t sve_umullt(T1 a, T2 b) + { + return sve_mull(llvm::Intrinsic::aarch64_sve_umullt, a, b); + } + + template + value_t sve_smlalb(T0 acc, T1 a, T2 b) + { + return sve_mlal(llvm::Intrinsic::aarch64_sve_smlalb, acc, a, b); + } + + template + value_t sve_smlalt(T0 acc, T1 a, T2 b) + { + return sve_mlal(llvm::Intrinsic::aarch64_sve_smlalt, acc, a, b); + } + + template + value_t sve_umlalt(T0 acc, T1 a, T2 b) + { + return sve_mlal(llvm::Intrinsic::aarch64_sve_umlalt, acc, a, b); + } + + template auto addp(T1 a, T2 b) { using T_vector = typename is_llvm_expr::type; diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index b7093a01bf..262df44b70 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -6265,6 +6265,15 @@ public: void MPYHHU(spu_opcode_t op) { +#ifdef ARCH_ARM64 + const auto [a, b] = get_vrs(op.ra, op.rb); + + if (m_use_sve2_128) + { + set_vr(op.rt, sve_umullt(bitcast(a), bitcast(b))); + return; + } +#endif set_vr(op.rt, (get_vr(op.ra) >> 16) * (get_vr(op.rb) >> 16)); } @@ -6295,11 +6304,29 @@ public: void MPYHHA(spu_opcode_t op) { +#ifdef ARCH_ARM64 + const auto [a, b] = get_vrs(op.ra, op.rb); + + if (m_use_sve2_128) + { + set_vr(op.rt, sve_smlalt(get_vr(op.rt), bitcast(a), bitcast(b))); + return; + } +#endif set_vr(op.rt, (get_vr(op.ra) >> 16) * (get_vr(op.rb) >> 16) + get_vr(op.rt)); } void MPYHHAU(spu_opcode_t op) { +#ifdef ARCH_ARM64 + const auto [a, b] = get_vrs(op.ra, op.rb); + + if (m_use_sve2_128) + { + set_vr(op.rt, sve_umlalt(get_vr(op.rt), bitcast(a), bitcast(b))); + return; + } +#endif set_vr(op.rt, (get_vr(op.ra) >> 16) * (get_vr(op.rb) >> 16) + get_vr(op.rt)); } @@ -6307,7 +6334,15 @@ public: { #ifdef ARCH_ARM64 const auto [a, b] = get_vrs(op.ra, op.rb); - set_vr(op.rt, smull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6))); + + if (m_use_sve2_128) + { + set_vr(op.rt, sve_smullb(bitcast(a), bitcast(b))); + } + else + { + set_vr(op.rt, smull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6))); + } #else set_vr(op.rt, (get_vr(op.ra) << 16 >> 16) * (get_vr(op.rb) << 16 >> 16)); #endif @@ -6320,6 +6355,15 @@ public: void MPYHH(spu_opcode_t op) { +#ifdef ARCH_ARM64 + const auto [a, b] = get_vrs(op.ra, op.rb); + + if (m_use_sve2_128) + { + set_vr(op.rt, sve_smullt(bitcast(a), bitcast(b))); + return; + } +#endif set_vr(op.rt, (get_vr(op.ra) >> 16) * (get_vr(op.rb) >> 16)); } @@ -6327,7 +6371,15 @@ public: { #ifdef ARCH_ARM64 const auto [a, b] = get_vrs(op.ra, op.rb); - set_vr(op.rt, smull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6)) >> 16); + + if (m_use_sve2_128) + { + set_vr(op.rt, sve_smullb(bitcast(a), bitcast(b)) >> 16); + } + else + { + set_vr(op.rt, smull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6)) >> 16); + } #else set_vr(op.rt, (get_vr(op.ra) << 16 >> 16) * (get_vr(op.rb) << 16 >> 16) >> 16); #endif @@ -6342,7 +6394,15 @@ public: { #ifdef ARCH_ARM64 const auto [a, b] = get_vrs(op.ra, op.rb); - set_vr(op.rt, umull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6))); + + if (m_use_sve2_128) + { + set_vr(op.rt, sve_umullb(bitcast(a), bitcast(b))); + } + else + { + set_vr(op.rt, umull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6))); + } #else set_vr(op.rt, mpyu(get_vr(op.ra), get_vr(op.rb))); #endif @@ -6495,7 +6555,14 @@ public: void MPYI(spu_opcode_t op) { #ifdef ARCH_ARM64 - set_vr(op.rt, smull(zshuffle(bitcast(get_vr(op.ra)), 0, 2, 4, 6), get_imm(op.si10))); + if (m_use_sve2_128) + { + set_vr(op.rt, sve_smullb(bitcast(get_vr(op.ra)), get_imm(op.si10))); + } + else + { + set_vr(op.rt, smull(zshuffle(bitcast(get_vr(op.ra)), 0, 2, 4, 6), get_imm(op.si10))); + } #else set_vr(op.rt, (get_vr(op.ra) << 16 >> 16) * get_imm(op.si10)); #endif @@ -6504,7 +6571,14 @@ public: void MPYUI(spu_opcode_t op) { #ifdef ARCH_ARM64 - set_vr(op.rt, umull(zshuffle(bitcast(get_vr(op.ra)), 0, 2, 4, 6), get_imm(op.si10))); + if (m_use_sve2_128) + { + set_vr(op.rt, sve_umullb(bitcast(get_vr(op.ra)), get_imm(op.si10))); + } + else + { + set_vr(op.rt, umull(zshuffle(bitcast(get_vr(op.ra)), 0, 2, 4, 6), get_imm(op.si10))); + } #else set_vr(op.rt, (get_vr(op.ra) << 16 >> 16) * (get_imm(op.si10) & 0xffff)); #endif @@ -7091,7 +7165,15 @@ public: { #ifdef ARCH_ARM64 const auto [a, b] = get_vrs(op.ra, op.rb); - set_vr(op.rt4, smull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6)) + get_vr(op.rc)); + + if (m_use_sve2_128) + { + set_vr(op.rt4, sve_smlalb(get_vr(op.rc), bitcast(a), bitcast(b))); + } + else + { + set_vr(op.rt4, smull(zshuffle(bitcast(a), 0, 2, 4, 6), zshuffle(bitcast(b), 0, 2, 4, 6)) + get_vr(op.rc)); + } #else set_vr(op.rt4, (get_vr(op.ra) << 16 >> 16) * (get_vr(op.rb) << 16 >> 16) + get_vr(op.rc)); #endif diff --git a/rpcs3/util/sysinfo.cpp b/rpcs3/util/sysinfo.cpp index b0be2edfdc..7748e41a09 100755 --- a/rpcs3/util/sysinfo.cpp +++ b/rpcs3/util/sysinfo.cpp @@ -531,13 +531,18 @@ std::string utils::get_system_info() } #ifdef ARCH_ARM64 - if (has_neon()) + if (!has_neon()) { - result += " | Neon"; + fmt::throw_exception("Neon support not present"); + } + + if (has_sve()) + { + fmt::append(result, " | SVE%s-%d", has_sve2() ? "2" : "", sve_length()); } else { - fmt::throw_exception("Neon support not present"); + result += " | Neon"; } #else