diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 10aa005290..c2ed545a47 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -3869,8 +3869,67 @@ public: void SELB(spu_opcode_t op) { - const auto c = get_vr(op.rc); - set_vr(op.rt4, (get_vr(op.ra) & ~c) | (get_vr(op.rb) & c)); + if (auto ei = llvm::dyn_cast_or_null(m_block->reg[op.rc])) + { + // Detect if the mask comes from a comparison instruction + if (ei->getOpcode() == llvm::Instruction::SExt && ei->getSrcTy()->isIntOrIntVectorTy(1)) + { + auto op0 = ei->getOperand(0); + auto typ = ei->getDestTy(); + auto op1 = m_block->reg[op.rb]; + auto op2 = m_block->reg[op.ra]; + + if (typ == get_type()) + { + if (op1 && op1->getType() == get_type() || op2 && op2->getType() == get_type()) + { + op1 = get_vr(op.rb).value; + op2 = get_vr(op.ra).value; + } + else + { + op1 = get_vr(op.rb).value; + op2 = get_vr(op.ra).value; + } + } + else if (typ == get_type()) + { + if (op1 && op1->getType() == get_type() || op2 && op2->getType() == get_type()) + { + op1 = get_vr(op.rb).value; + op2 = get_vr(op.ra).value; + } + else + { + op1 = get_vr(op.rb).value; + op2 = get_vr(op.ra).value; + } + } + else if (typ == get_type()) + { + op1 = get_vr(op.rb).value; + op2 = get_vr(op.ra).value; + } + else if (typ == get_type()) + { + op1 = get_vr(op.rb).value; + op2 = get_vr(op.ra).value; + } + else + { + LOG_ERROR(SPU, "[0x%x] SELB: unknown cast destination type", m_pos); + op0 = nullptr; + } + + if (op0 && op1 && op2) + { + set_vr(op.rt4, m_ir->CreateSelect(op0, op1, op2)); + return; + } + } + } + + set_vr(op.rt4, merge(get_vr(op.rc), get_vr(op.rb), get_vr(op.ra))); } void SHUFB(spu_opcode_t op)