Merge pull request #619 from steve-lunarg/opcode-specific-promote
HLSL: opcode specific promotion rules for interlocked ops
This commit is contained in:
commit
302e619e4e
109
Test/baseResults/hlsl.promote.atomic.frag.out
Normal file
109
Test/baseResults/hlsl.promote.atomic.frag.out
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
hlsl.promote.atomic.frag
|
||||||
|
Shader version: 450
|
||||||
|
gl_FragCoord origin is upper left
|
||||||
|
0:? Sequence
|
||||||
|
0:5 Function Definition: main( (temp 4-component vector of float)
|
||||||
|
0:5 Function Parameters:
|
||||||
|
0:? Sequence
|
||||||
|
0:13 move second child to first child (temp int)
|
||||||
|
0:13 'Orig' (temp int)
|
||||||
|
0:13 Convert uint to int (temp int)
|
||||||
|
0:13 imageAtomicAdd (temp uint)
|
||||||
|
0:13 's_uintbuff' (layout(r32ui ) uniform uimageBuffer)
|
||||||
|
0:13 'Loc' (temp int)
|
||||||
|
0:13 Convert int to uint (temp uint)
|
||||||
|
0:13 'Inc' (temp int)
|
||||||
|
0:15 Sequence
|
||||||
|
0:15 move second child to first child (temp 4-component vector of float)
|
||||||
|
0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
|
||||||
|
0:? Constant:
|
||||||
|
0:? 0.000000
|
||||||
|
0:? 0.000000
|
||||||
|
0:? 0.000000
|
||||||
|
0:? 0.000000
|
||||||
|
0:15 Branch: Return
|
||||||
|
0:? Linker Objects
|
||||||
|
0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
|
||||||
|
0:? 's_uintbuff' (layout(r32ui ) uniform uimageBuffer)
|
||||||
|
|
||||||
|
|
||||||
|
Linked fragment stage:
|
||||||
|
|
||||||
|
|
||||||
|
Shader version: 450
|
||||||
|
gl_FragCoord origin is upper left
|
||||||
|
0:? Sequence
|
||||||
|
0:5 Function Definition: main( (temp 4-component vector of float)
|
||||||
|
0:5 Function Parameters:
|
||||||
|
0:? Sequence
|
||||||
|
0:13 move second child to first child (temp int)
|
||||||
|
0:13 'Orig' (temp int)
|
||||||
|
0:13 Convert uint to int (temp int)
|
||||||
|
0:13 imageAtomicAdd (temp uint)
|
||||||
|
0:13 's_uintbuff' (layout(r32ui ) uniform uimageBuffer)
|
||||||
|
0:13 'Loc' (temp int)
|
||||||
|
0:13 Convert int to uint (temp uint)
|
||||||
|
0:13 'Inc' (temp int)
|
||||||
|
0:15 Sequence
|
||||||
|
0:15 move second child to first child (temp 4-component vector of float)
|
||||||
|
0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
|
||||||
|
0:? Constant:
|
||||||
|
0:? 0.000000
|
||||||
|
0:? 0.000000
|
||||||
|
0:? 0.000000
|
||||||
|
0:? 0.000000
|
||||||
|
0:15 Branch: Return
|
||||||
|
0:? Linker Objects
|
||||||
|
0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
|
||||||
|
0:? 's_uintbuff' (layout(r32ui ) uniform uimageBuffer)
|
||||||
|
|
||||||
|
// Module Version 10000
|
||||||
|
// Generated by (magic number): 80001
|
||||||
|
// Id's are bound by 31
|
||||||
|
|
||||||
|
Capability Shader
|
||||||
|
Capability SampledBuffer
|
||||||
|
1: ExtInstImport "GLSL.std.450"
|
||||||
|
MemoryModel Logical GLSL450
|
||||||
|
EntryPoint Fragment 4 "main" 27
|
||||||
|
ExecutionMode 4 OriginUpperLeft
|
||||||
|
Name 4 "main"
|
||||||
|
Name 8 "Orig"
|
||||||
|
Name 12 "s_uintbuff"
|
||||||
|
Name 13 "Loc"
|
||||||
|
Name 15 "Inc"
|
||||||
|
Name 27 "@entryPointOutput"
|
||||||
|
Decorate 12(s_uintbuff) DescriptorSet 0
|
||||||
|
Decorate 27(@entryPointOutput) Location 0
|
||||||
|
2: TypeVoid
|
||||||
|
3: TypeFunction 2
|
||||||
|
6: TypeInt 32 1
|
||||||
|
7: TypePointer Function 6(int)
|
||||||
|
9: TypeInt 32 0
|
||||||
|
10: TypeImage 9(int) Buffer nonsampled format:R32ui
|
||||||
|
11: TypePointer UniformConstant 10
|
||||||
|
12(s_uintbuff): 11(ptr) Variable UniformConstant
|
||||||
|
18: 9(int) Constant 0
|
||||||
|
19: TypePointer Image 9(int)
|
||||||
|
21: 9(int) Constant 1
|
||||||
|
24: TypeFloat 32
|
||||||
|
25: TypeVector 24(float) 4
|
||||||
|
26: TypePointer Output 25(fvec4)
|
||||||
|
27(@entryPointOutput): 26(ptr) Variable Output
|
||||||
|
28: 24(float) Constant 0
|
||||||
|
29: 25(fvec4) ConstantComposite 28 28 28 28
|
||||||
|
4(main): 2 Function None 3
|
||||||
|
5: Label
|
||||||
|
8(Orig): 7(ptr) Variable Function
|
||||||
|
13(Loc): 7(ptr) Variable Function
|
||||||
|
15(Inc): 7(ptr) Variable Function
|
||||||
|
14: 6(int) Load 13(Loc)
|
||||||
|
16: 6(int) Load 15(Inc)
|
||||||
|
17: 9(int) Bitcast 16
|
||||||
|
20: 19(ptr) ImageTexelPointer 12(s_uintbuff) 14 18
|
||||||
|
22: 9(int) AtomicIAdd 20 21 18 17
|
||||||
|
23: 6(int) Bitcast 22
|
||||||
|
Store 8(Orig) 23
|
||||||
|
Store 27(@entryPointOutput) 29
|
||||||
|
Return
|
||||||
|
FunctionEnd
|
||||||
17
Test/hlsl.promote.atomic.frag
Normal file
17
Test/hlsl.promote.atomic.frag
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
RWBuffer<uint> s_uintbuff; // UINT RWBuffer ...
|
||||||
|
|
||||||
|
float4 main() : SV_Target
|
||||||
|
{
|
||||||
|
int Loc; // ... with INT variables
|
||||||
|
int Inc;
|
||||||
|
int Orig;
|
||||||
|
|
||||||
|
// This must select the uint flavor of SPIR-V atomic op, and promote
|
||||||
|
// the other arguments as required. The output value from the
|
||||||
|
// imageAtomicAdd AST will be converted to an int for 'Orig'.
|
||||||
|
InterlockedAdd(s_uintbuff[Loc], Inc, Orig);
|
||||||
|
|
||||||
|
return float4(0,0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ TVariable* TParseContextBase::getEditableVariable(const char* name)
|
|||||||
const TFunction* TParseContextBase::selectFunction(
|
const TFunction* TParseContextBase::selectFunction(
|
||||||
const TVector<const TFunction*> candidateList,
|
const TVector<const TFunction*> candidateList,
|
||||||
const TFunction& call,
|
const TFunction& call,
|
||||||
std::function<bool(const TType& from, const TType& to)> convertible,
|
std::function<bool(const TType& from, const TType& to, TOperator op, int arg)> convertible,
|
||||||
std::function<bool(const TType& from, const TType& to1, const TType& to2)> better,
|
std::function<bool(const TType& from, const TType& to1, const TType& to2)> better,
|
||||||
/* output */ bool& tie)
|
/* output */ bool& tie)
|
||||||
{
|
{
|
||||||
@ -356,13 +356,13 @@ const TFunction* TParseContextBase::selectFunction(
|
|||||||
bool viable = true;
|
bool viable = true;
|
||||||
for (int param = 0; param < candidate.getParamCount(); ++param) {
|
for (int param = 0; param < candidate.getParamCount(); ++param) {
|
||||||
if (candidate[param].type->getQualifier().isParamInput()) {
|
if (candidate[param].type->getQualifier().isParamInput()) {
|
||||||
if (! convertible(*call[param].type, *candidate[param].type)) {
|
if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) {
|
||||||
viable = false;
|
viable = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (candidate[param].type->getQualifier().isParamOutput()) {
|
if (candidate[param].type->getQualifier().isParamOutput()) {
|
||||||
if (! convertible(*candidate[param].type, *call[param].type)) {
|
if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) {
|
||||||
viable = false;
|
viable = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4875,7 +4875,7 @@ const TFunction* TParseContext::findFunction400(const TSourceLoc& loc, const TFu
|
|||||||
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
|
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
|
||||||
|
|
||||||
// can 'from' convert to 'to'?
|
// can 'from' convert to 'to'?
|
||||||
const auto convertible = [this](const TType& from, const TType& to) -> bool {
|
const auto convertible = [this](const TType& from, const TType& to, TOperator, int) -> bool {
|
||||||
if (from == to)
|
if (from == to)
|
||||||
return true;
|
return true;
|
||||||
if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
|
if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
|
||||||
|
|||||||
@ -167,7 +167,7 @@ protected:
|
|||||||
|
|
||||||
// see implementation for detail
|
// see implementation for detail
|
||||||
const TFunction* selectFunction(const TVector<const TFunction*>, const TFunction&,
|
const TFunction* selectFunction(const TVector<const TFunction*>, const TFunction&,
|
||||||
std::function<bool(const TType&, const TType&)>,
|
std::function<bool(const TType&, const TType&, TOperator, int arg)>,
|
||||||
std::function<bool(const TType&, const TType&, const TType&)>,
|
std::function<bool(const TType&, const TType&, const TType&)>,
|
||||||
/* output */ bool& tie);
|
/* output */ bool& tie);
|
||||||
|
|
||||||
|
|||||||
@ -163,6 +163,7 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
{"hlsl.partialInit.frag", "PixelShaderFunction"},
|
{"hlsl.partialInit.frag", "PixelShaderFunction"},
|
||||||
{"hlsl.pp.line.frag", "main"},
|
{"hlsl.pp.line.frag", "main"},
|
||||||
{"hlsl.precise.frag", "main"},
|
{"hlsl.precise.frag", "main"},
|
||||||
|
{"hlsl.promote.atomic.frag", "main"},
|
||||||
{"hlsl.promote.binary.frag", "main"},
|
{"hlsl.promote.binary.frag", "main"},
|
||||||
{"hlsl.promote.vec1.frag", "main"},
|
{"hlsl.promote.vec1.frag", "main"},
|
||||||
{"hlsl.promotions.frag", "main"},
|
{"hlsl.promotions.frag", "main"},
|
||||||
|
|||||||
@ -4394,8 +4394,10 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
|
|||||||
return candidateList[0];
|
return candidateList[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool allowOnlyUpConversions = true;
|
||||||
|
|
||||||
// can 'from' convert to 'to'?
|
// can 'from' convert to 'to'?
|
||||||
const auto convertible = [this](const TType& from, const TType& to) -> bool {
|
const auto convertible = [&](const TType& from, const TType& to, TOperator op, int arg) -> bool {
|
||||||
if (from == to)
|
if (from == to)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -4404,9 +4406,33 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
|
|||||||
from.isStruct() || to.isStruct())
|
from.isStruct() || to.isStruct())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case EOpInterlockedAdd:
|
||||||
|
case EOpInterlockedAnd:
|
||||||
|
case EOpInterlockedCompareExchange:
|
||||||
|
case EOpInterlockedCompareStore:
|
||||||
|
case EOpInterlockedExchange:
|
||||||
|
case EOpInterlockedMax:
|
||||||
|
case EOpInterlockedMin:
|
||||||
|
case EOpInterlockedOr:
|
||||||
|
case EOpInterlockedXor:
|
||||||
|
// We do not promote the texture or image type for these ocodes. Normally that would not
|
||||||
|
// be an issue because it's a buffer, but we haven't decomposed the opcode yet, and at this
|
||||||
|
// stage it's merely e.g, a basic integer type.
|
||||||
|
//
|
||||||
|
// Instead, we want to promote other arguments, but stay within the same family. In other
|
||||||
|
// words, InterlockedAdd(RWBuffer<int>, ...) will always use the int flavor, never the uint flavor,
|
||||||
|
// but it is allowed to promote its other arguments.
|
||||||
|
if (arg == 0)
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// basic types have to be convertible
|
// basic types have to be convertible
|
||||||
if (! intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType(), EOpFunctionCall))
|
if (allowOnlyUpConversions)
|
||||||
return false;
|
if (! intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType(), EOpFunctionCall))
|
||||||
|
return false;
|
||||||
|
|
||||||
// shapes have to be convertible
|
// shapes have to be convertible
|
||||||
if ((from.isScalarOrVec1() && to.isScalarOrVec1()) ||
|
if ((from.isScalarOrVec1() && to.isScalarOrVec1()) ||
|
||||||
@ -4472,6 +4498,14 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
|
|||||||
// send to the generic selector
|
// send to the generic selector
|
||||||
const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie);
|
const TFunction* bestMatch = selectFunction(candidateList, call, convertible, better, tie);
|
||||||
|
|
||||||
|
if (bestMatch == nullptr) {
|
||||||
|
// If there is nothing selected by allowing only up-conversions (to a larger linearize() value),
|
||||||
|
// we instead try down-conversions, which are valid in HLSL, but not preferred if there are any
|
||||||
|
// upconversions possible.
|
||||||
|
allowOnlyUpConversions = false;
|
||||||
|
bestMatch = selectFunction(candidateList, call, convertible, better, tie);
|
||||||
|
}
|
||||||
|
|
||||||
if (bestMatch == nullptr) {
|
if (bestMatch == nullptr) {
|
||||||
error(loc, "no matching overloaded function found", call.getName().c_str(), "");
|
error(loc, "no matching overloaded function found", call.getName().c_str(), "");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user