Merge #930 (pr/wave-lane-state)
This commit is contained in:
commit
d04084b6d5
|
|
@ -1309,7 +1309,7 @@ public static partial class Gen5SpirvTranslator
|
|||
StoreS(register.Value, value);
|
||||
}
|
||||
|
||||
private enum SharedMemoryPhase { None, Read, Write }
|
||||
private enum SharedMemoryPhase { None, Read, Write, Unknown }
|
||||
|
||||
private bool TryEmitBlock(
|
||||
IReadOnlyList<ShaderBlock> blocks,
|
||||
|
|
@ -1318,10 +1318,13 @@ public static partial class Gen5SpirvTranslator
|
|||
{
|
||||
error = string.Empty;
|
||||
var block = blocks[blockIndex];
|
||||
// One guest wave can span two host subgroups. Keep its shared-memory phases ordered.
|
||||
// Restrict added barriers to a single block, where all invocations follow the same path.
|
||||
var synchronizeSharedMemory = _emulateWave64 && blocks.Count == 1;
|
||||
var sharedMemoryPhase = SharedMemoryPhase.None;
|
||||
// One guest wave can span two host subgroups; the guest orders its lanes' LDS accesses
|
||||
// by executing in lockstep, so a change between reading and writing needs a barrier
|
||||
// between the halves. Every guest branch condition is wave-uniform (EXEC and VCC tests
|
||||
// go through the wave mask, SCC is scalar), so every block is entered by the whole wave
|
||||
// and may hold a barrier. Another block may have left either phase behind.
|
||||
var synchronizeSharedMemory = _emulateWave64;
|
||||
var sharedMemoryPhase = blocks.Count == 1 ? SharedMemoryPhase.None : SharedMemoryPhase.Unknown;
|
||||
for (var index = block.StartIndex; index < block.EndIndex; index++)
|
||||
{
|
||||
var instruction = _request.Program.Instructions[index];
|
||||
|
|
@ -6917,14 +6920,35 @@ public static partial class Gen5SpirvTranslator
|
|||
Store(ScalarPointer(register), value);
|
||||
if (register is 106 or 107)
|
||||
{
|
||||
Store(_vcc, IsWaveMaskActive(LoadS64(106)));
|
||||
if (_waveLaneCount != 32 || register == 106)
|
||||
{
|
||||
Store(_vcc, IsLaneSetInMaskRegisters(106));
|
||||
}
|
||||
}
|
||||
else if (register is 126 or 127)
|
||||
{
|
||||
Store(_exec, IsWaveMaskActive(LoadS64(126)));
|
||||
if (_waveLaneCount != 32 || register == 126)
|
||||
{
|
||||
Store(_exec, IsLaneSetInMaskRegisters(126));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In wave32 a lane mask is its low register alone (VCC_HI and EXEC_HI are ordinary SGPRs),
|
||||
// so the lane's bit is tested on one dword instead of a composed 64-bit mask.
|
||||
private uint IsLaneSetInMaskRegisters(uint lowRegister)
|
||||
{
|
||||
if (_waveLaneCount != 32)
|
||||
{
|
||||
return IsWaveMaskActive(LoadS64(lowRegister));
|
||||
}
|
||||
|
||||
var laneBit = _subgroupInvocationIdInput == 0
|
||||
? UInt(1)
|
||||
: ShiftLeftLogical(UInt(1), GuestWaveLane());
|
||||
return IsNotZero(BitwiseAnd(LoadS(lowRegister), laneBit));
|
||||
}
|
||||
|
||||
private void StoreV(uint register, uint value, bool guardWithExec = true)
|
||||
{
|
||||
if (guardWithExec)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public sealed class Gen5WaveMaskSpirvTests
|
|||
// the per-lane _vcc predicate from the wave mask via IsWaveMaskActive.
|
||||
var spirv = Compile([0x7C04_0300u]);
|
||||
|
||||
// The lane's bit in single-lane emulation is the 64-bit constant 1, so the
|
||||
// The lane's bit in single-lane emulation is the constant 1, so the
|
||||
// predicate is `(mask & 1) != 0`. The whole-word bug emitted `mask != 0`
|
||||
// with no such mask. Require the lane-bit AND to be present.
|
||||
Assert.True(
|
||||
|
|
@ -47,26 +47,27 @@ public sealed class Gen5WaveMaskSpirvTests
|
|||
Assert.NotEmpty(spirv);
|
||||
}
|
||||
|
||||
// True when the module contains an OpBitwiseAnd whose operand is a 64-bit
|
||||
// constant of value 1 — the current-lane bit that IsCurrentLaneSet masks the
|
||||
// wave mask with before the non-zero test.
|
||||
// True when the module contains an OpBitwiseAnd whose operand is an integer
|
||||
// constant of value 1 — the current-lane bit that the lane test masks the
|
||||
// wave mask with before the non-zero test. A wave64 mask is a 64-bit value
|
||||
// and a wave32 mask is a single dword, so either width counts.
|
||||
private static bool ContainsLaneBitMaskedWaveTest(byte[] spirv)
|
||||
{
|
||||
var laneBitConstIds = new HashSet<uint>();
|
||||
|
||||
// Pass 1: collect 64-bit OpConstant result-ids whose value is 1.
|
||||
// Pass 1: collect OpConstant result-ids whose integer value is 1.
|
||||
foreach (var (op, wordCount, offset) in EnumerateInstructions(spirv))
|
||||
{
|
||||
// OpConstant = 43; a 64-bit constant occupies 5 words
|
||||
// (opcode, resultType, resultId, valueLow, valueHigh).
|
||||
if (op != 43 || wordCount != 5)
|
||||
// OpConstant = 43; a 32-bit constant occupies 4 words and a 64-bit one
|
||||
// 5 (opcode, resultType, resultId, valueLow[, valueHigh]).
|
||||
if (op != 43 || wordCount is not (4 or 5))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var resultId = ReadWord(spirv, offset + 8);
|
||||
var low = ReadWord(spirv, offset + 12);
|
||||
var high = ReadWord(spirv, offset + 16);
|
||||
var high = wordCount == 5 ? ReadWord(spirv, offset + 16) : 0u;
|
||||
if (low == 1 && high == 0)
|
||||
{
|
||||
laneBitConstIds.Add(resultId);
|
||||
|
|
|
|||
Loading…
Reference in New Issue