mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 03:46:53 +02:00
shader: compute DPP permute, rotate, mirror and share lanes with bit-field and XOR ops
This commit is contained in:
@@ -4,25 +4,16 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
|
||||
DppTargetLane EmitDppPermTargetLane(EmitterState& state, uint32_t subid, uint32_t control,
|
||||
uint32_t lane_bits) {
|
||||
const auto lane_mask = (1u << lane_bits) - 1u;
|
||||
const auto group_base = state.builder.AllocateId();
|
||||
const auto lane = state.builder.AllocateId();
|
||||
const auto shift = state.builder.AllocateId();
|
||||
const auto selected0 = state.builder.AllocateId();
|
||||
const auto selected = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), group_base, subid,
|
||||
ConstantU32(state, ~lane_mask));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, lane_mask));
|
||||
state.builder.AddFunction(spv::OpIMul, TypeU32(state), shift, lane,
|
||||
ConstantU32(state, lane_bits));
|
||||
state.builder.AddFunction(spv::OpShiftRightLogical, TypeU32(state), selected0,
|
||||
ConstantU32(state, control), shift);
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), selected, selected0,
|
||||
ConstantU32(state, lane_mask));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, group_base, selected);
|
||||
return {target, ConstantBool(state, true)};
|
||||
// Each lane of a group takes its lane_bits-wide source index from control.
|
||||
const auto lane = Binary(state, spv::OpBitwiseAnd, TypeU32(state), subid,
|
||||
ConstantU32(state, (1u << lane_bits) - 1u));
|
||||
const auto selected = EmitNative<spv::OpBitFieldUExtract, IR::Type::U32>(
|
||||
state, ConstantU32(state, control),
|
||||
Binary(state, spv::OpIMul, TypeU32(state), lane, ConstantU32(state, lane_bits)),
|
||||
ConstantU32(state, lane_bits));
|
||||
return {EmitNative<spv::OpBitFieldInsert, IR::Type::U32>(
|
||||
state, subid, selected, ConstantU32(state, 0), ConstantU32(state, lane_bits)),
|
||||
ConstantBool(state, true)};
|
||||
}
|
||||
|
||||
DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uint32_t amount,
|
||||
@@ -53,42 +44,19 @@ DppTargetLane EmitDppRowShiftTargetLane(EmitterState& state, uint32_t subid, uin
|
||||
|
||||
DppTargetLane EmitDppRowRotateRightTargetLane(EmitterState& state, uint32_t subid,
|
||||
uint32_t amount) {
|
||||
const auto row = state.builder.AllocateId();
|
||||
const auto lane = state.builder.AllocateId();
|
||||
const auto in_high = state.builder.AllocateId();
|
||||
const auto minus = state.builder.AllocateId();
|
||||
const auto plus = state.builder.AllocateId();
|
||||
const auto selected = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), row, subid,
|
||||
ConstantU32(state, 0xfffffff0u));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, 15));
|
||||
state.builder.AddFunction(spv::OpUGreaterThanEqual, TypeBool(state), in_high, lane,
|
||||
ConstantU32(state, amount));
|
||||
state.builder.AddFunction(spv::OpISub, TypeU32(state), minus, lane, ConstantU32(state, amount));
|
||||
state.builder.AddFunction(spv::OpIAdd, TypeU32(state), plus, lane,
|
||||
ConstantU32(state, 16u - amount));
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), selected, in_high, minus, plus);
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, row, selected);
|
||||
return {target, ConstantBool(state, true)};
|
||||
// Rotation wraps within the row, so only the low four lane bits change.
|
||||
const auto rotated = Binary(state, spv::OpISub, TypeU32(state), subid, ConstantU32(state, amount));
|
||||
return {EmitNative<spv::OpBitFieldInsert, IR::Type::U32>(state, subid, rotated,
|
||||
ConstantU32(state, 0),
|
||||
ConstantU32(state, 4)),
|
||||
ConstantBool(state, true)};
|
||||
}
|
||||
|
||||
DppTargetLane EmitDppMirrorTargetLane(EmitterState& state, uint32_t subid, bool half_row) {
|
||||
const auto base_mask = half_row ? 0xfffffff8u : 0xfffffff0u;
|
||||
const auto lane_mask = half_row ? 7u : 15u;
|
||||
const auto base = state.builder.AllocateId();
|
||||
const auto lane = state.builder.AllocateId();
|
||||
const auto mirrored = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), base, subid,
|
||||
ConstantU32(state, base_mask));
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), lane, subid,
|
||||
ConstantU32(state, lane_mask));
|
||||
state.builder.AddFunction(spv::OpISub, TypeU32(state), mirrored, ConstantU32(state, lane_mask),
|
||||
lane);
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, base, mirrored);
|
||||
return {target, ConstantBool(state, true)};
|
||||
// Mirroring lane i of a row or half row reads lane (size - 1 - i), which flips its low bits.
|
||||
return {Binary(state, spv::OpBitwiseXor, TypeU32(state), subid,
|
||||
ConstantU32(state, half_row ? 7u : 15u)),
|
||||
ConstantBool(state, true)};
|
||||
}
|
||||
|
||||
DppTargetLane EmitDppTargetLane(EmitterState& state, const IR::DppMoveFlags& flags) {
|
||||
@@ -117,13 +85,10 @@ DppTargetLane EmitDppTargetLane(EmitterState& state, const IR::DppMoveFlags& fla
|
||||
}
|
||||
// row_share:N reads lane N of the caller's row of 16.
|
||||
if (control >= 0x150u && control <= 0x15fu) {
|
||||
const auto row = state.builder.AllocateId();
|
||||
const auto target = state.builder.AllocateId();
|
||||
state.builder.AddFunction(spv::OpBitwiseAnd, TypeU32(state), row, subid,
|
||||
ConstantU32(state, 0xfffffff0u));
|
||||
state.builder.AddFunction(spv::OpBitwiseOr, TypeU32(state), target, row,
|
||||
ConstantU32(state, control & 0xfu));
|
||||
return {target, ConstantBool(state, true)};
|
||||
return {EmitNative<spv::OpBitFieldInsert, IR::Type::U32>(
|
||||
state, subid, ConstantU32(state, control & 0xfu), ConstantU32(state, 0),
|
||||
ConstantU32(state, 4)),
|
||||
ConstantBool(state, true)};
|
||||
}
|
||||
if (control >= 0x160u && control <= 0x16fu) {
|
||||
const auto target = state.builder.AllocateId();
|
||||
|
||||
@@ -27298,6 +27298,35 @@ TestCase VectorDppRowShare(u32 wave_size) {
|
||||
return test;
|
||||
}
|
||||
|
||||
// row_mirror, row_half_mirror and row_ror read lanes within the row; v1 = 100 + lane.
|
||||
TestCase VectorDppMirrorAndRotate(u32 wave_size) {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = wave_size == 32 ? "VectorDppMirrorAndRotateWave32" : "VectorDppMirrorAndRotateWave64";
|
||||
auto &code = test.code;
|
||||
AppendVMovU32(&code, 1, 100);
|
||||
code.push_back(EncodeVop2(0x25, 1, Vgpr(0), 1));
|
||||
for (const u32 control : {0x140u, 0x141u, 0x121u, 0x125u, 0x12fu}) {
|
||||
code.push_back(EncodeVop1(0x01, 2, 250));
|
||||
code.push_back(EncodeVop1Dpp(1, control));
|
||||
AppendStoreVgprAtLaneDwordOffset(&code, 2, 0, u32(test.expected.size()));
|
||||
for (u32 lane = 0; lane < wave_size; ++lane) {
|
||||
const u32 source = control == 0x140u ? (lane | 15u) - (lane & 15u)
|
||||
: control == 0x141u ? (lane | 7u) - (lane & 7u)
|
||||
: (lane & ~15u) | ((lane - (control & 15u)) & 15u);
|
||||
test.expected.push_back(100 + source);
|
||||
}
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.opcodes = {O::V_MOV_B32, O::V_ADD_NC_U32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.compute_info.threads_num[0] = wave_size;
|
||||
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.has_compute_info = true;
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase VectorDppBankMaskPreservesDestination() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -43058,6 +43087,8 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(VectorDppRowXmask);
|
||||
cases.push_back(VectorDppRowShare(32));
|
||||
cases.push_back(VectorDppRowShare(64));
|
||||
cases.push_back(VectorDppMirrorAndRotate(32));
|
||||
cases.push_back(VectorDppMirrorAndRotate(64));
|
||||
cases.push_back(ComputeWave64Minimum(false));
|
||||
cases.push_back(ComputeWave64Minimum(true));
|
||||
AddCase(VectorDppBankMaskPreservesDestination);
|
||||
@@ -49148,6 +49179,8 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, VectorDppRowXmask());
|
||||
RunCase(&vulkan, VectorDppRowShare(32));
|
||||
RunCase(&vulkan, VectorDppRowShare(64));
|
||||
RunCase(&vulkan, VectorDppMirrorAndRotate(32));
|
||||
RunCase(&vulkan, VectorDppMirrorAndRotate(64));
|
||||
RunCase(&vulkan, VectorDppBankMaskPreservesDestination());
|
||||
RunCase(&vulkan, VectorDppBoundsControlZeroPreservesDestination());
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user