mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
[AGC] Correct VReadlaneB32 decode and emission (#237)
VReadlaneB32 (VOP3 0x360) had two bugs: 1. Decode: VOP3 decode always set destinations = Vector(word & 0xFF). For VReadlaneB32, bits 0-7 are unused — the scalar destination is in bits 8-14. Now decodes as Scalar((word >> 8) & 0x7F). 2. Emission: VReadlaneB32 was in the VMovB32 fall-through group, just returning GetRawSource(instruction, 0) — reading the current lane's value. By ISA, sdst = vsrc0[lane(src1)], which requires reading a different lane's value. Now uses SPIR-V GroupNonUniformBroadcast(scope=Subgroup, value=src0, lane=src1) when subgroup operations are available, with a fallback to the current-lane simplification when not. 3. Routing: TryEmitVectorAlu called TryGetVectorDestination first, which checks for VectorRegister kind. With the scalar destination fix, VReadlaneB32 now routes to a new TryEmitReadlane handler before the vector destination check. 4. Subgroup capability: UsesSubgroupShuffle now includes VReadlaneB32 so GroupNonUniform capability is enabled when needed. Verified: dotnet build 0 errors/0 warnings, 26/26 tests pass, ShaderDump all programs behaved as expected.
This commit is contained in:
@@ -24,6 +24,11 @@ public static partial class Gen5SpirvTranslator
|
|||||||
return TryEmitVectorCompare(instruction, out error);
|
return TryEmitVectorCompare(instruction, out error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instruction.Opcode == "VReadlaneB32")
|
||||||
|
{
|
||||||
|
return TryEmitReadlane(instruction, out error);
|
||||||
|
}
|
||||||
|
|
||||||
if (!TryGetVectorDestination(instruction, out var destination))
|
if (!TryGetVectorDestination(instruction, out var destination))
|
||||||
{
|
{
|
||||||
error = "missing vector destination";
|
error = "missing vector destination";
|
||||||
@@ -34,7 +39,6 @@ public static partial class Gen5SpirvTranslator
|
|||||||
switch (instruction.Opcode)
|
switch (instruction.Opcode)
|
||||||
{
|
{
|
||||||
case "VMovB32":
|
case "VMovB32":
|
||||||
case "VReadlaneB32":
|
|
||||||
case "VReadfirstlaneB32":
|
case "VReadfirstlaneB32":
|
||||||
result = GetRawSource(instruction, 0);
|
result = GetRawSource(instruction, 0);
|
||||||
break;
|
break;
|
||||||
@@ -2365,6 +2369,42 @@ public static partial class Gen5SpirvTranslator
|
|||||||
StoreWaveMask(106, carry);
|
StoreWaveMask(106, carry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryEmitReadlane(
|
||||||
|
Gen5ShaderInstruction instruction,
|
||||||
|
out string error)
|
||||||
|
{
|
||||||
|
error = string.Empty;
|
||||||
|
if (instruction.Destinations.Count == 0 ||
|
||||||
|
instruction.Destinations[0].Kind != Gen5OperandKind.ScalarRegister)
|
||||||
|
{
|
||||||
|
error = "VReadlaneB32 expects scalar destination";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var destination = instruction.Destinations[0].Value;
|
||||||
|
var src0 = GetRawSource(instruction, 0);
|
||||||
|
|
||||||
|
if (_subgroupInvocationIdInput != 0)
|
||||||
|
{
|
||||||
|
// sdst = vsrc0[lane(src1)] — broadcast from the specified lane.
|
||||||
|
var laneSelect = GetRawSource(instruction, 1);
|
||||||
|
var broadcast = _module.AddInstruction(
|
||||||
|
SpirvOp.GroupNonUniformBroadcast,
|
||||||
|
_uintType,
|
||||||
|
UInt(3), // Subgroup scope
|
||||||
|
src0,
|
||||||
|
laneSelect);
|
||||||
|
StoreS(destination, broadcast);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback: no subgroup ops, read current lane's value.
|
||||||
|
StoreS(destination, src0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private uint EmitPermlane16(
|
private uint EmitPermlane16(
|
||||||
Gen5ShaderInstruction instruction,
|
Gen5ShaderInstruction instruction,
|
||||||
bool exchangeRows)
|
bool exchangeRows)
|
||||||
|
|||||||
@@ -2507,7 +2507,7 @@ public static partial class Gen5SpirvTranslator
|
|||||||
|
|
||||||
private bool UsesSubgroupShuffle() =>
|
private bool UsesSubgroupShuffle() =>
|
||||||
_state.Program.Instructions.Any(instruction =>
|
_state.Program.Instructions.Any(instruction =>
|
||||||
instruction.Opcode is "VPermlane16B32" or "VPermlanex16B32");
|
instruction.Opcode is "VPermlane16B32" or "VPermlanex16B32" or "VReadlaneB32");
|
||||||
|
|
||||||
private bool UsesWaveControl() =>
|
private bool UsesWaveControl() =>
|
||||||
_state.Program.Instructions.Any(instruction =>
|
_state.Program.Instructions.Any(instruction =>
|
||||||
|
|||||||
@@ -1467,6 +1467,12 @@ public static class Gen5ShaderTranslator
|
|||||||
Gen5Operand.Source((extra >> 18) & 0x1FF, literal),
|
Gen5Operand.Source((extra >> 18) & 0x1FF, literal),
|
||||||
];
|
];
|
||||||
destinations = [Gen5Operand.Vector(word & 0xFF)];
|
destinations = [Gen5Operand.Vector(word & 0xFF)];
|
||||||
|
if (opcode == "VReadlaneB32")
|
||||||
|
{
|
||||||
|
// VReadlaneB32 writes to scalar destination (bits 8-14), not vector.
|
||||||
|
// Bits 0-7 are unused for this opcode.
|
||||||
|
destinations = [Gen5Operand.Scalar((word >> 8) & 0x7F)];
|
||||||
|
}
|
||||||
var isVop3B = IsVop3BOpcode((word >> 16) & 0x3FF);
|
var isVop3B = IsVop3BOpcode((word >> 16) & 0x3FF);
|
||||||
control = new Gen5Vop3Control(
|
control = new Gen5Vop3Control(
|
||||||
isVop3B ? 0 : (word >> 8) & 0x7,
|
isVop3B ? 0 : (word >> 8) & 0x7,
|
||||||
|
|||||||
Reference in New Issue
Block a user