mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-29 23:41:19 -06:00
Neo: bit and alu instructions (#4332)
This commit is contained in:
parent
7755e98a2f
commit
76729835d7
@ -275,7 +275,11 @@ public:
|
||||
void V_MUL_LO_U32(const GcnInst& inst);
|
||||
void V_MUL_HI_U32(bool is_signed, const GcnInst& inst);
|
||||
void V_MAD_U64_U32(const GcnInst& inst);
|
||||
void V_LSHL_ADD_U32(const GcnInst& inst);
|
||||
void V_ADD_LSHL_U32(const GcnInst& inst);
|
||||
void V_ADD3_U32(const GcnInst& inst);
|
||||
void V_LSHL_OR_B32(const GcnInst& inst);
|
||||
void V_AND_OR_B32(const GcnInst& inst);
|
||||
void V_OR3_B32(const GcnInst& inst);
|
||||
|
||||
// Vector interpolation
|
||||
|
||||
@ -458,6 +458,14 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
|
||||
return V_MAD_U64_U32(inst);
|
||||
case Opcode::V_ADD3_U32:
|
||||
return V_ADD3_U32(inst);
|
||||
case Opcode::V_ADD_LSHL_U32:
|
||||
return V_ADD_LSHL_U32(inst);
|
||||
case Opcode::V_LSHL_ADD_U32:
|
||||
return V_LSHL_ADD_U32(inst);
|
||||
case Opcode::V_LSHL_OR_B32:
|
||||
return V_LSHL_OR_B32(inst);
|
||||
case Opcode::V_AND_OR_B32:
|
||||
return V_AND_OR_B32(inst);
|
||||
case Opcode::V_OR3_B32:
|
||||
return V_OR3_B32(inst);
|
||||
case Opcode::V_NOP:
|
||||
@ -1552,6 +1560,30 @@ void Translator::V_MAD_U64_U32(const GcnInst& inst) {
|
||||
ir.SetVcc(did_overflow);
|
||||
}
|
||||
|
||||
void Translator::V_ADD_LSHL_U32(const GcnInst& inst) {
|
||||
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
|
||||
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
|
||||
const auto src2 = GetSrc<IR::U32>(inst.src[2]);
|
||||
|
||||
const auto shift = ir.BitwiseAnd(src2, ir.Imm32(0x1F));
|
||||
|
||||
const auto result = ir.ShiftLeftLogical(ir.IAdd(src0, src1), shift);
|
||||
|
||||
SetDst(inst.dst[0], result);
|
||||
}
|
||||
|
||||
void Translator::V_LSHL_ADD_U32(const GcnInst& inst) {
|
||||
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
|
||||
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
|
||||
const auto src2 = GetSrc<IR::U32>(inst.src[2]);
|
||||
|
||||
const auto shift = ir.BitwiseAnd(src1, ir.Imm32(0x1F));
|
||||
|
||||
const auto result = ir.IAdd(ir.ShiftLeftLogical(src0, shift), src2);
|
||||
|
||||
SetDst(inst.dst[0], result);
|
||||
}
|
||||
|
||||
void Translator::V_ADD3_U32(const GcnInst& inst) {
|
||||
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
|
||||
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
|
||||
@ -1560,6 +1592,28 @@ void Translator::V_ADD3_U32(const GcnInst& inst) {
|
||||
SetDst(inst.dst[0], ir.IAdd(src0, ir.IAdd(src1, src2)));
|
||||
}
|
||||
|
||||
void Translator::V_LSHL_OR_B32(const GcnInst& inst) {
|
||||
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
|
||||
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
|
||||
const auto src2 = GetSrc<IR::U32>(inst.src[2]);
|
||||
|
||||
const auto shift = ir.BitwiseAnd(src1, ir.Imm32(0x1F));
|
||||
|
||||
const auto result = ir.BitwiseOr(ir.ShiftLeftLogical(src0, shift), src2);
|
||||
|
||||
SetDst(inst.dst[0], result);
|
||||
}
|
||||
|
||||
void Translator::V_AND_OR_B32(const GcnInst& inst) {
|
||||
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
|
||||
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
|
||||
const auto src2 = GetSrc<IR::U32>(inst.src[2]);
|
||||
|
||||
const auto result = ir.BitwiseOr(ir.BitwiseAnd(src0, src1), src2);
|
||||
|
||||
SetDst(inst.dst[0], result);
|
||||
}
|
||||
|
||||
void Translator::V_OR3_B32(const GcnInst& inst) {
|
||||
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
|
||||
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
|
||||
|
||||
@ -244,3 +244,83 @@ TEST_F(GcnTest, or3_u32_4) {
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0xD7575757);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_1) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array<u32,3>{0xF0F0F0F0, 0x07070707, 0x11111111});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0x11111111);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_2) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetOmod(Omod::Mul2).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array{0x40404040, 0x40404040, 0x40404040});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0x40404040);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_3) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetClamp(true).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array{0x40404040, 0x40404040, 0x40404040});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0x40404040);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_4) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetNeg({1,0,0}).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array<u32,3>{0x07070707, 0x11111111, 0xF0F0F0F0});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0xF1F1F1F1);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_5) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetNeg({1,0,0}).SetAbs({1,0,0}).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array<u32,3>{0x77777777, 0xB0B0B0B0, 0x11111111});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0xB1313131);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_6) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetOmod(Omod::Mul2).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array<u32,3>{0x40404040, 0xB0B0B0B0, 0x11111111});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0x11111111);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_7) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetOmod(Omod::Div2).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array<u32,3>{0xB0B0B0B0, 0x77777777, 0x40404040});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0x70707070);
|
||||
}
|
||||
|
||||
TEST_F(GcnTest, and_or_b32_8) {
|
||||
auto runner = gcn_test::Runner::instance().value();
|
||||
|
||||
auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_AND_OR_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetAbs({1,1,0}).Get());
|
||||
auto result = runner->run<u32>(spirv, std::array<u32,3>{0xB0B0B0B0, 0x11111111, 0x11111111});
|
||||
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(*result, 0x11111111);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user