[SpirvTranslator] Add DsMinF32 and DsMaxF32 instructions
This commit is contained in:
parent
776c97cebc
commit
537ecb83e0
|
|
@ -1251,6 +1251,29 @@ public static partial class Gen5SpirvTranslator
|
|||
private bool TryEmitGlobalDataShareAtomic(Gen5ShaderInstruction instruction, Gen5DataShareControl control, out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
if (instruction.Opcode is "DsMinF32" or "DsMaxF32")
|
||||
{
|
||||
if (instruction.Sources.Count < 3)
|
||||
{
|
||||
error = $"missing GDS operands for {instruction.Opcode}";
|
||||
return false;
|
||||
}
|
||||
|
||||
var floatIndex = GlobalDataShareIndex(GetRawSource(instruction, 0), control.SingleOffsetBytes);
|
||||
EmitExecConditional(() =>
|
||||
{
|
||||
EmitConditional(IsBlockWordInRange(_globalDataShare, floatIndex), () =>
|
||||
EmitDataShareFloatAtomic(
|
||||
BlockWordPointer(_globalDataShare, floatIndex),
|
||||
GetRawSource(instruction, 1),
|
||||
GetRawSource(instruction, 2),
|
||||
instruction.Opcode == "DsMaxF32",
|
||||
scope: 1,
|
||||
semantics: 0x48));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
var atomicOp = instruction.Opcode switch
|
||||
{
|
||||
"DsAddU32" or "DsAddRtnU32" => SpirvOp.AtomicIAdd,
|
||||
|
|
|
|||
|
|
@ -1844,6 +1844,27 @@ public static partial class Gen5SpirvTranslator
|
|||
out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
if (instruction.Opcode is "DsMinF32" or "DsMaxF32")
|
||||
{
|
||||
if (instruction.Sources.Count < 3)
|
||||
{
|
||||
error = $"missing LDS operands for {instruction.Opcode}";
|
||||
return false;
|
||||
}
|
||||
|
||||
var floatAddress = GetRawSource(instruction, 0);
|
||||
var floatPointer = LdsPointer(floatAddress, control.SingleOffsetBytes);
|
||||
EmitExecConditional(() =>
|
||||
EmitDataShareFloatAtomic(
|
||||
floatPointer,
|
||||
GetRawSource(instruction, 1),
|
||||
GetRawSource(instruction, 2),
|
||||
instruction.Opcode == "DsMaxF32",
|
||||
scope: 2,
|
||||
semantics: 0x108));
|
||||
return true;
|
||||
}
|
||||
|
||||
var atomicOp = instruction.Opcode switch
|
||||
{
|
||||
"DsAddU32" or "DsAddRtnU32" => SpirvOp.AtomicIAdd,
|
||||
|
|
@ -1891,6 +1912,65 @@ public static partial class Gen5SpirvTranslator
|
|||
return true;
|
||||
}
|
||||
|
||||
private void EmitDataShareFloatAtomic(
|
||||
uint pointer,
|
||||
uint data,
|
||||
uint compare,
|
||||
bool maxValue,
|
||||
uint scope,
|
||||
uint semantics)
|
||||
{
|
||||
var preheader = _module.AllocateId();
|
||||
var header = _module.AllocateId();
|
||||
var continueLabel = _module.AllocateId();
|
||||
var mergeLabel = _module.AllocateId();
|
||||
var exchanged = _module.AllocateId();
|
||||
|
||||
_module.AddStatement(SpirvOp.Branch, preheader);
|
||||
_module.AddLabel(preheader);
|
||||
var initial = _module.AddInstruction(
|
||||
SpirvOp.AtomicLoad,
|
||||
_uintType,
|
||||
pointer,
|
||||
UInt(scope),
|
||||
UInt(semantics));
|
||||
_module.AddStatement(SpirvOp.Branch, header);
|
||||
|
||||
_module.AddLabel(header);
|
||||
var observed = _module.AddInstruction(
|
||||
SpirvOp.Phi,
|
||||
_uintType,
|
||||
initial,
|
||||
preheader,
|
||||
exchanged,
|
||||
continueLabel);
|
||||
var observedFloat = Bitcast(_floatType, observed);
|
||||
var compareFloat = Bitcast(_floatType, compare);
|
||||
var replace = _module.AddInstruction(
|
||||
maxValue ? SpirvOp.FOrdGreaterThan : SpirvOp.FOrdLessThan,
|
||||
_boolType,
|
||||
maxValue ? observedFloat : compareFloat,
|
||||
maxValue ? compareFloat : observedFloat);
|
||||
var next = _module.AddInstruction(SpirvOp.Select, _uintType, replace, data, observed);
|
||||
|
||||
_module.AddStatement(
|
||||
SpirvOp.AtomicCompareExchange,
|
||||
_uintType,
|
||||
exchanged,
|
||||
pointer,
|
||||
UInt(scope),
|
||||
UInt(semantics),
|
||||
UInt((semantics & ~0x8u) | 0x2u),
|
||||
next,
|
||||
observed);
|
||||
var success = _module.AddInstruction(SpirvOp.IEqual, _boolType, exchanged, observed);
|
||||
_module.AddStatement(SpirvOp.LoopMerge, mergeLabel, continueLabel, 0);
|
||||
_module.AddStatement(SpirvOp.BranchConditional, success, mergeLabel, continueLabel);
|
||||
_module.AddLabel(continueLabel);
|
||||
_module.AddStatement(SpirvOp.Branch, header);
|
||||
_module.AddLabel(mergeLabel);
|
||||
}
|
||||
|
||||
// Maps the AMD atomic-op name suffix shared by buffer/image atomics to a SPIR-V opcode.
|
||||
// Inc/Dec approximate the AMD wrap-clamp semantics (MEM = tmp >= DATA ? 0 : tmp + 1),
|
||||
// which is exact for the common 0xFFFFFFFF clamp operand.
|
||||
|
|
|
|||
|
|
@ -1196,6 +1196,8 @@ public static partial class Gen5ShaderTranslator
|
|||
0x0E => "DsWrite2B32",
|
||||
0x0F => "DsWrite2St64B32",
|
||||
0x10 => "DsCmpstB32",
|
||||
0x12 => "DsMinF32",
|
||||
0x13 => "DsMaxF32",
|
||||
0x20 => "DsAddRtnU32",
|
||||
0x21 => "DsSubRtnU32",
|
||||
0x23 => "DsIncRtnU32",
|
||||
|
|
@ -1683,6 +1685,7 @@ public static partial class Gen5ShaderTranslator
|
|||
{
|
||||
"DsAddU32" or "DsSubU32" or "DsIncU32" or "DsDecU32" or
|
||||
"DsMinI32" or "DsMaxI32" or "DsMinU32" or "DsMaxU32" or
|
||||
"DsMinF32" or "DsMaxF32" or
|
||||
"DsAndB32" or "DsOrB32" or "DsXorB32" or "DsCmpstB32" or
|
||||
"DsAddRtnU32" or "DsSubRtnU32" or "DsIncRtnU32" or "DsDecRtnU32" or
|
||||
"DsMinRtnI32" or "DsMaxRtnI32" or "DsMinRtnU32" or "DsMaxRtnU32" or
|
||||
|
|
@ -2159,6 +2162,13 @@ public static partial class Gen5ShaderTranslator
|
|||
Gen5Operand.Vector(vectorData0),
|
||||
Gen5Operand.Vector(vectorData1),
|
||||
],
|
||||
// GFX10 DS_MIN/MAX_F32 use DATA0 as the replacement value and
|
||||
// DATA1 as the floating-point compare operand.
|
||||
"DsMinF32" or "DsMaxF32" => [
|
||||
Gen5Operand.Vector(vectorAddress),
|
||||
Gen5Operand.Vector(vectorData0),
|
||||
Gen5Operand.Vector(vectorData1),
|
||||
],
|
||||
_ when IsDataShareAtomic(opcode) => [
|
||||
Gen5Operand.Vector(vectorAddress),
|
||||
Gen5Operand.Vector(vectorData0),
|
||||
|
|
|
|||
|
|
@ -84,6 +84,21 @@ public sealed class Gen5ShaderAtomicDecodeTests
|
|||
Assert.Equal(new[] { Gen5Operand.Vector(3) }, instruction.Destinations);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0xD8480004u, "DsMinF32")]
|
||||
[InlineData(0xD84C0008u, "DsMaxF32")]
|
||||
public void DsFloatMinMax_KeepReplacementAndCompareOperands(uint word, string opcode)
|
||||
{
|
||||
// DATA0 is the replacement value and DATA1 is the float compare operand.
|
||||
var instruction = DecodeSingle(word, 0x00010907);
|
||||
|
||||
Assert.Equal(opcode, instruction.Opcode);
|
||||
Assert.Equal(
|
||||
new[] { Gen5Operand.Vector(7), Gen5Operand.Vector(9), Gen5Operand.Vector(1) },
|
||||
instruction.Sources);
|
||||
Assert.Empty(instruction.Destinations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DsCmpstRtnB32_OrdersComparatorBeforeNewValue()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue