HLSL: opcode specific promotion rules for interlocked ops
PR #577 addresses most but not all of the intrinsic promotion problems. This PR resolves all known cases in the remainder. Interlocked ops need special promotion rules because at the time of function selection, the first argument has not been converted to a buffer object. It's just an int or uint, but you don't want to convert THAT argument, because that implies converting the buffer object itself. Rather, you can convert other arguments, but want to stay in the same "family" of functions. E.g, if the first interlocked arg is a uint, use only the uint family, never the int family, you can convert the other args as you please. This PR allows making such opcode and arg specific choices by passing the op and arg to the convertible lambda. The code in the new test "hlsl.promote.atomic.frag" would not compile without this change, but it must compile. Also, it provides better handling of downconversions (to "worse" types), which are permitted in HLSL. The existing method of selecting upconversions is unchanged, but if that doesn't find any valid ones, then it will allow downconversions. In effect this always uses an upconversion if there is one.
This commit is contained in:
@@ -4394,8 +4394,10 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
|
||||
return candidateList[0];
|
||||
}
|
||||
|
||||
bool allowOnlyUpConversions = true;
|
||||
|
||||
// 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)
|
||||
return true;
|
||||
|
||||
@@ -4404,9 +4406,33 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
|
||||
from.isStruct() || to.isStruct())
|
||||
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
|
||||
if (! intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType(), EOpFunctionCall))
|
||||
return false;
|
||||
if (allowOnlyUpConversions)
|
||||
if (! intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType(), EOpFunctionCall))
|
||||
return false;
|
||||
|
||||
// shapes have to be convertible
|
||||
if ((from.isScalarOrVec1() && to.isScalarOrVec1()) ||
|
||||
@@ -4472,6 +4498,14 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
|
||||
// send to the generic selector
|
||||
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) {
|
||||
error(loc, "no matching overloaded function found", call.getName().c_str(), "");
|
||||
return nullptr;
|
||||
|
||||
Reference in New Issue
Block a user