[GPU] Map half-wave shuffle lanes into the host subgroup
This commit is contained in:
parent
5c9b409e18
commit
5cac7c7812
|
|
@ -3955,7 +3955,7 @@ public static partial class Gen5SpirvTranslator
|
|||
{
|
||||
targetLane = BitwiseAnd(targetLane, UInt(31));
|
||||
}
|
||||
var shuffled = ShuffleLane(value, targetLane);
|
||||
var shuffled = ShuffleHalfWaveLane(value, targetLane);
|
||||
if (control.FetchInactive)
|
||||
{
|
||||
return shuffled;
|
||||
|
|
@ -3968,7 +3968,7 @@ public static partial class Gen5SpirvTranslator
|
|||
UInt(1),
|
||||
UInt(0));
|
||||
var sourceActive = IsNotZero(
|
||||
ShuffleLane(activeWord, targetLane));
|
||||
ShuffleHalfWaveLane(activeWord, targetLane));
|
||||
return _module.AddInstruction(
|
||||
SpirvOp.Select,
|
||||
_uintType,
|
||||
|
|
@ -3991,7 +3991,7 @@ public static partial class Gen5SpirvTranslator
|
|||
// operations are limited to a single half-wave for some encodings, so we
|
||||
// must not clamp wave64 lanes to 31; use the full lane mask instead.
|
||||
safeTarget = BitwiseAnd(safeTarget, UInt(_waveLaneCount == 64 ? 63u : 31u));
|
||||
var shuffled = ShuffleLane(value, safeTarget);
|
||||
var shuffled = ShuffleHalfWaveLane(value, safeTarget);
|
||||
|
||||
var sourceAvailable = inRange;
|
||||
if (!control.FetchInactive)
|
||||
|
|
@ -4002,7 +4002,7 @@ public static partial class Gen5SpirvTranslator
|
|||
Load(_boolType, _exec),
|
||||
UInt(1),
|
||||
UInt(0));
|
||||
var shuffledActive = ShuffleLane(activeWord, safeTarget);
|
||||
var shuffledActive = ShuffleHalfWaveLane(activeWord, safeTarget);
|
||||
sourceAvailable = _module.AddInstruction(
|
||||
SpirvOp.LogicalAnd,
|
||||
_boolType,
|
||||
|
|
@ -5124,11 +5124,9 @@ public static partial class Gen5SpirvTranslator
|
|||
}
|
||||
|
||||
var targetLane = IAdd(rowBase, selector);
|
||||
// Mask to guest wave size — on Radeon hardware DPP is limited to a
|
||||
// single half-wave for some encodings, but we must not clamp wave64
|
||||
// lanes to 31; use the full lane mask instead.
|
||||
// Select a guest lane first; ShuffleHalfWaveLane maps it to the host subgroup.
|
||||
targetLane = BitwiseAnd(targetLane, UInt(_waveLaneCount == 64 ? 63u : 31u));
|
||||
var shuffled = ShuffleLane(value, targetLane);
|
||||
var shuffled = ShuffleHalfWaveLane(value, targetLane);
|
||||
var fetchInactive = (control.OperandSelect & 1) != 0;
|
||||
if (fetchInactive)
|
||||
{
|
||||
|
|
@ -5142,7 +5140,7 @@ public static partial class Gen5SpirvTranslator
|
|||
UInt(1),
|
||||
UInt(0));
|
||||
var sourceActive = IsNotZero(
|
||||
ShuffleLane(activeWord, targetLane));
|
||||
ShuffleHalfWaveLane(activeWord, targetLane));
|
||||
return _module.AddInstruction(
|
||||
SpirvOp.Select,
|
||||
_uintType,
|
||||
|
|
|
|||
|
|
@ -8303,6 +8303,15 @@ public static partial class Gen5SpirvTranslator
|
|||
? value
|
||||
: _module.AddInstruction(SpirvOp.GroupNonUniformShuffle, _uintType, UInt(3), value, lane);
|
||||
|
||||
// DPP row/quad operations and PERMLANE16 never cross a 32-lane half-wave.
|
||||
// Guest lanes 32..63 belong to the second host subgroup on 32-lane devices;
|
||||
// using those guest indices directly in OpGroupNonUniformShuffle is undefined.
|
||||
// Preserve the current physical half on devices whose subgroup is wider than 32.
|
||||
private uint ShuffleHalfWaveLane(uint value, uint guestLane) =>
|
||||
_subgroupInvocationIdInput == 0 ? value : ShuffleLane(value,
|
||||
BitwiseOr(BitwiseAnd(Load(_uintType, _subgroupInvocationIdInput), UInt(0xFFFF_FFE0)),
|
||||
BitwiseAnd(guestLane, UInt(31))));
|
||||
|
||||
private uint CurrentLaneBit()
|
||||
{
|
||||
if (_subgroupInvocationIdInput == 0)
|
||||
|
|
|
|||
|
|
@ -17,12 +17,16 @@ public sealed class WaveShuffleDeviceTests(HeadlessVulkanFixture fixture, ITestO
|
|||
: IClassFixture<HeadlessVulkanFixture>
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Dpp8")]
|
||||
[InlineData("Dpp16")]
|
||||
[InlineData("Permlane16")]
|
||||
[InlineData("Permlanex16")]
|
||||
[InlineData("Reduction")]
|
||||
public void Wave64Shuffle_PreservesUpperHalf(string operation)
|
||||
[InlineData("Dpp8", 32)]
|
||||
[InlineData("Dpp8", 64)]
|
||||
[InlineData("Dpp16", 32)]
|
||||
[InlineData("Dpp16", 64)]
|
||||
[InlineData("Permlane16", 32)]
|
||||
[InlineData("Permlane16", 64)]
|
||||
[InlineData("Permlanex16", 32)]
|
||||
[InlineData("Permlanex16", 64)]
|
||||
[InlineData("Reduction", 64)]
|
||||
public void WaveShuffle_PreservesEachHalf(string operation, uint waveSize)
|
||||
{
|
||||
var vulkan = fixture.Vulkan;
|
||||
if (!GatePrerequisites.Ready(vulkan, shaderInt64: true)) return;
|
||||
|
|
@ -79,7 +83,7 @@ public sealed class WaveShuffleDeviceTests(HeadlessVulkanFixture fixture, ITestO
|
|||
var (plan, resources, layout) = Prepare(Program([.. instructions]));
|
||||
var request = new ShaderCompileRequest(plan, resources, layout)
|
||||
{
|
||||
LocalSizeX = 8, LocalSizeY = 8, ThreadCountX = 8, ThreadCountY = 8, WaveSize = 64,
|
||||
LocalSizeX = 8, LocalSizeY = waveSize / 8, ThreadCountX = 8, ThreadCountY = waveSize / 8, WaveSize = waveSize,
|
||||
};
|
||||
Assert.True(Gen5SpirvTranslator.TryCompileProgram(request, out var shader, out var error), error);
|
||||
using var harness = new ImageTestHarness(vulkan);
|
||||
|
|
@ -90,7 +94,7 @@ public sealed class WaveShuffleDeviceTests(HeadlessVulkanFixture fixture, ITestO
|
|||
harness.Run(() => runner.Dispatch(registers,
|
||||
new Dictionary<DescriptorBindingKind, GpuBuffer[]> { [DescriptorBindingKind.Buffers] = [result] }, 1));
|
||||
var actual = runner.ReadBack(result, 0, 256);
|
||||
for (uint lane = 0; lane < 64; lane++)
|
||||
for (uint lane = 0; lane < waveSize; lane++)
|
||||
{
|
||||
var expected = operation switch
|
||||
{
|
||||
|
|
@ -104,6 +108,6 @@ public sealed class WaveShuffleDeviceTests(HeadlessVulkanFixture fixture, ITestO
|
|||
Assert.Equal(expected, BinaryPrimitives.ReadUInt32LittleEndian(actual.AsSpan((int)lane * 4)));
|
||||
}
|
||||
harness.AssertNoValidationMessages();
|
||||
output.WriteLine($"Verified {operation} on {vulkan.DeviceName}.");
|
||||
output.WriteLine($"Verified wave{waveSize} {operation} on {vulkan.DeviceName}.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue