Commit 26d31453 by steve-lunarg

HLSL default function parameters

This PR adds support for default function parameters in the following cases: 1. Simple constants, such as void fn(int x, float myparam = 3) 2. Expressions that can be const folded, such a ... myparam = sin(some_const) 3. Initializer lists that can be const folded, such as ... float2 myparam = {1,2} New tests are added: hlsl.params.default.frag and hlsl.params.default.err.frag (for testing error situations, such as ambiguity or non-const-foldable). In order to avoid sampler method ambiguity, the hlsl better() lambda now considers sampler matches. Previously, all sampler types looked identical since only the basic type of EbtSampler was considered.
parent 807a0d9e
hlsl.intrinsics.negative.frag hlsl.intrinsics.negative.frag
ERROR: 0:10: 'determinant' : no matching overloaded function found ERROR: 0:10: 'determinant' : no matching overloaded function found
ERROR: 0:12: 'f32tof16' : unimplemented intrinsic: handle natively ERROR: 0:12: 'f32tof16' : unimplemented intrinsic: handle natively
ERROR: 0:23: 'length' : ambiguous best function under implicit type conversion
ERROR: 0:25: 'normalize' : ambiguous best function under implicit type conversion
ERROR: 0:26: 'reflect' : ambiguous best function under implicit type conversion
ERROR: 0:27: 'refract' : ambiguous best function under implicit type conversion
ERROR: 0:28: 'refract' : no matching overloaded function found ERROR: 0:28: 'refract' : no matching overloaded function found
ERROR: 0:30: 'transpose' : no matching overloaded function found ERROR: 0:30: 'transpose' : no matching overloaded function found
ERROR: 0:39: 'GetRenderTargetSamplePosition' : no matching overloaded function found ERROR: 0:39: 'GetRenderTargetSamplePosition' : no matching overloaded function found
...@@ -59,7 +63,7 @@ ERROR: 0:133: 'normalize' : no matching overloaded function found ...@@ -59,7 +63,7 @@ ERROR: 0:133: 'normalize' : no matching overloaded function found
ERROR: 0:133: 'reflect' : no matching overloaded function found ERROR: 0:133: 'reflect' : no matching overloaded function found
ERROR: 0:133: 'refract' : no matching overloaded function found ERROR: 0:133: 'refract' : no matching overloaded function found
ERROR: 0:133: 'reversebits' : no matching overloaded function found ERROR: 0:133: 'reversebits' : no matching overloaded function found
ERROR: 60 compilation errors. No code generated. ERROR: 64 compilation errors. No code generated.
Shader version: 450 Shader version: 450
......
uniform int4 ui4;
static const int cia = -4;
static const int cib = -42;
// ERROR: Ambiguous with fn1 below.
// int4 fn1(int4 p0) { return int4(1,2,3,4); }
int4 fn1(int4 p0, bool b1, bool b2 = false) {
return p0;
}
int4 fn1(int4 p0,
int4 p1 : FOO = int4(-1,-2,-3, cia),
int p2[2] : BAR = { int(1), 2 },
int p3 = abs(cib) )
{
return p0 + p1 + p2[0] + p3;
}
// These should not be ambiguous if given either an int or a float explicit second parameter.
int4 fn2(int4 p0, int x = 3)
{
return int4(10,11,12,13);
}
int4 fn2(int4 p0, float x = sin(3.3)) // OK to have a const expression as a default value
{
return p0 + int4(20,21,22,23);
}
void fn3(int p0 = 3) { }
int4 main() : SV_Target0
{
int myarray[2] = {30,31};
fn3();
fn3(5);
return fn1(100) +
fn1(101, ui4) +
fn1(102, ui4, myarray) +
fn1(103, ui4, myarray, 99) +
fn1(104, false) +
fn1(105, false, true) +
fn2(110, 11.11) + // calls int4, float form
fn2(111, 12); // calls int4, int form
}
uniform int4 ui4;
uniform float ufvar;
static const int cia = -4;
static const int cib = -42;
int4 fn1(int4 p0) { return int4(1,2,3,4); }
int4 fn1(int4 p0, bool b1, bool b2 = false) {
return p0;
}
int4 fn1(int4 p0,
int4 p1 : FOO = int4(-1,-2,-3, cia),
int p2[2] : BAR = { int(1), 2 },
int p3 = abs(cib) )
{
return p0 + p1 + p2[0] + p3;
}
// These should not be ambiguous if given either an int or a float explicit second parameter.
int4 fn2(int4 p0, int x = 3)
{
return int4(10,11,12,13);
}
int4 fn2(int4 p0, float x = ufvar) // ERROR: non-const expression
{
return p0 + int4(20,21,22,23);
}
void fn3(int p0 = 5, int p1) // ERROR no-default param after default param
{
}
int4 main() : SV_Target0
{
int myarray[2] = {30,31};
return fn1(100) + // ERROR: ambiguous
fn1(101, ui4) +
fn1(102, ui4, myarray) +
fn1(103, ui4, myarray, 99) +
fn1(104, false) +
fn1(105, false, true) +
fn2(112) + // ERROR: ambiguous
fn2(110, 11.11) + // calls int4, float form
fn2(111, 12); // calls int4, int form
}
...@@ -629,6 +629,9 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) ...@@ -629,6 +629,9 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
// //
TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
{ {
if (aggrNode == nullptr)
return aggrNode;
if (! areAllChildConst(aggrNode)) if (! areAllChildConst(aggrNode))
return aggrNode; return aggrNode;
......
...@@ -348,13 +348,18 @@ const TFunction* TParseContextBase::selectFunction( ...@@ -348,13 +348,18 @@ const TFunction* TParseContextBase::selectFunction(
for (auto it = candidateList.begin(); it != candidateList.end(); ++it) { for (auto it = candidateList.begin(); it != candidateList.end(); ++it) {
const TFunction& candidate = *(*it); const TFunction& candidate = *(*it);
// to even be a potential match, number of arguments has to match // to even be a potential match, number of arguments must be >= the number of
if (call.getParamCount() != candidate.getParamCount()) // fixed (non-default) parameters, and <= the total (including parameter with defaults).
if (call.getParamCount() < candidate.getFixedParamCount() ||
call.getParamCount() > candidate.getParamCount())
continue; continue;
// see if arguments are convertible // see if arguments are convertible
bool viable = true; bool viable = true;
for (int param = 0; param < candidate.getParamCount(); ++param) {
// The call can have fewer parameters than the candidate, if some have defaults.
const int paramCount = std::min(call.getParamCount(), candidate.getParamCount());
for (int param = 0; param < paramCount; ++param) {
if (candidate[param].type->getQualifier().isParamInput()) { if (candidate[param].type->getQualifier().isParamInput()) {
if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) { if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) {
viable = false; viable = false;
...@@ -382,7 +387,7 @@ const TFunction* TParseContextBase::selectFunction( ...@@ -382,7 +387,7 @@ const TFunction* TParseContextBase::selectFunction(
return viableCandidates.front(); return viableCandidates.front();
// 4. find best... // 4. find best...
auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool { const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
// is call -> can2 better than call -> can1 for any parameter // is call -> can2 better than call -> can1 for any parameter
bool hasBetterParam = false; bool hasBetterParam = false;
for (int param = 0; param < call.getParamCount(); ++param) { for (int param = 0; param < call.getParamCount(); ++param) {
...@@ -394,6 +399,16 @@ const TFunction* TParseContextBase::selectFunction( ...@@ -394,6 +399,16 @@ const TFunction* TParseContextBase::selectFunction(
return hasBetterParam; return hasBetterParam;
}; };
const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
// is call -> can2 equivalent to call -> can1 for all the call parameters?
for (int param = 0; param < call.getParamCount(); ++param) {
if (better(*call[param].type, *can1[param].type, *can2[param].type) ||
better(*call[param].type, *can2[param].type, *can1[param].type))
return false;
}
return true;
};
const TFunction* incumbent = viableCandidates.front(); const TFunction* incumbent = viableCandidates.front();
for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) { for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) {
const TFunction& candidate = *(*it); const TFunction& candidate = *(*it);
...@@ -406,7 +421,10 @@ const TFunction* TParseContextBase::selectFunction( ...@@ -406,7 +421,10 @@ const TFunction* TParseContextBase::selectFunction(
if (incumbent == *it) if (incumbent == *it)
continue; continue;
const TFunction& candidate = *(*it); const TFunction& candidate = *(*it);
if (betterParam(*incumbent, candidate))
// In the case of default parameters, it may have an identical initial set, which is
// also ambiguous
if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate))
tie = true; tie = true;
} }
......
...@@ -295,6 +295,7 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) ...@@ -295,6 +295,7 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
op = copyOf.op; op = copyOf.op;
defined = copyOf.defined; defined = copyOf.defined;
prototyped = copyOf.prototyped; prototyped = copyOf.prototyped;
defaultParamCount = copyOf.defaultParamCount;
} }
TFunction* TFunction::clone() const TFunction* TFunction::clone() const
......
...@@ -191,6 +191,7 @@ protected: ...@@ -191,6 +191,7 @@ protected:
struct TParameter { struct TParameter {
TString *name; TString *name;
TType* type; TType* type;
TIntermTyped* defaultValue;
void copyParam(const TParameter& param) void copyParam(const TParameter& param)
{ {
if (param.name) if (param.name)
...@@ -198,6 +199,7 @@ struct TParameter { ...@@ -198,6 +199,7 @@ struct TParameter {
else else
name = 0; name = 0;
type = param.type->clone(); type = param.type->clone();
defaultValue = param.defaultValue;
} }
}; };
...@@ -209,12 +211,12 @@ public: ...@@ -209,12 +211,12 @@ public:
explicit TFunction(TOperator o) : explicit TFunction(TOperator o) :
TSymbol(0), TSymbol(0),
op(o), op(o),
defined(false), prototyped(false) { } defined(false), prototyped(false), defaultParamCount(0) { }
TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) : TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
TSymbol(name), TSymbol(name),
mangledName(*name + '('), mangledName(*name + '('),
op(tOp), op(tOp),
defined(false), prototyped(false) { returnType.shallowCopy(retType); } defined(false), prototyped(false), defaultParamCount(0) { returnType.shallowCopy(retType); }
virtual TFunction* clone() const; virtual TFunction* clone() const;
virtual ~TFunction(); virtual ~TFunction();
...@@ -226,6 +228,9 @@ public: ...@@ -226,6 +228,9 @@ public:
assert(writable); assert(writable);
parameters.push_back(p); parameters.push_back(p);
p.type->appendMangledName(mangledName); p.type->appendMangledName(mangledName);
if (p.defaultValue != nullptr)
defaultParamCount++;
} }
virtual const TString& getMangledName() const { return mangledName; } virtual const TString& getMangledName() const { return mangledName; }
...@@ -238,7 +243,13 @@ public: ...@@ -238,7 +243,13 @@ public:
virtual void setPrototyped() { assert(writable); prototyped = true; } virtual void setPrototyped() { assert(writable); prototyped = true; }
virtual bool isPrototyped() const { return prototyped; } virtual bool isPrototyped() const { return prototyped; }
// Return total number of parameters
virtual int getParamCount() const { return static_cast<int>(parameters.size()); } virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
// Return number of parameters with default values.
virtual int getDefaultParamCount() const { return defaultParamCount; }
// Return number of fixed parameters (without default values)
virtual int getFixedParamCount() const { return getParamCount() - getDefaultParamCount(); }
virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; } virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
virtual const TParameter& operator[](int i) const { return parameters[i]; } virtual const TParameter& operator[](int i) const { return parameters[i]; }
...@@ -255,6 +266,7 @@ protected: ...@@ -255,6 +266,7 @@ protected:
TOperator op; TOperator op;
bool defined; bool defined;
bool prototyped; bool prototyped;
int defaultParamCount;
}; };
// //
......
...@@ -160,6 +160,8 @@ INSTANTIATE_TEST_CASE_P( ...@@ -160,6 +160,8 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.numericsuffixes.frag", "main"}, {"hlsl.numericsuffixes.frag", "main"},
{"hlsl.numthreads.comp", "main_aux1"}, {"hlsl.numthreads.comp", "main_aux1"},
{"hlsl.overload.frag", "PixelShaderFunction"}, {"hlsl.overload.frag", "PixelShaderFunction"},
{"hlsl.params.default.frag", "main"},
{"hlsl.params.default.negative.frag", "main"},
{"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"},
......
...@@ -1776,9 +1776,55 @@ bool HlslGrammar::acceptFunctionParameters(TFunction& function) ...@@ -1776,9 +1776,55 @@ bool HlslGrammar::acceptFunctionParameters(TFunction& function)
return true; return true;
} }
// default_parameter_declaration
// : EQUAL conditional_expression
// : EQUAL initializer
bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTyped*& node)
{
node = nullptr;
// Valid not to have a default_parameter_declaration
if (!acceptTokenClass(EHTokAssign))
return true;
if (!acceptConditionalExpression(node)) {
if (!acceptInitializer(node))
return false;
// For initializer lists, we have to const-fold into a constructor for the type, so build
// that.
TFunction* constructor = parseContext.handleConstructorCall(token.loc, type);
if (constructor == nullptr) // cannot construct
return false;
TIntermTyped* arguments = nullptr;
for (int i=0; i<int(node->getAsAggregate()->getSequence().size()); i++)
parseContext.handleFunctionArgument(constructor, arguments, node->getAsAggregate()->getSequence()[i]->getAsTyped());
node = parseContext.handleFunctionCall(token.loc, constructor, node);
}
// If this is simply a constant, we can use it directly.
if (node->getAsConstantUnion())
return true;
// Otherwise, it has to be const-foldable.
TIntermTyped* origNode = node;
node = intermediate.fold(node->getAsAggregate());
if (node != nullptr && origNode != node)
return true;
parseContext.error(token.loc, "invalid default parameter value", "", "");
return false;
}
// parameter_declaration // parameter_declaration
// : fully_specified_type post_decls // : fully_specified_type post_decls [ = default_parameter_declaration ]
// | fully_specified_type identifier array_specifier post_decls // | fully_specified_type identifier array_specifier post_decls [ = default_parameter_declaration ]
// //
bool HlslGrammar::acceptParameterDeclaration(TFunction& function) bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
{ {
...@@ -1806,9 +1852,19 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function) ...@@ -1806,9 +1852,19 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
// post_decls // post_decls
acceptPostDecls(type->getQualifier()); acceptPostDecls(type->getQualifier());
TIntermTyped* defaultValue;
if (!acceptDefaultParameterDeclaration(*type, defaultValue))
return false;
parseContext.paramFix(*type); parseContext.paramFix(*type);
TParameter param = { idToken.string, type }; // If any prior parameters have default values, all the parameters after that must as well.
if (defaultValue == nullptr && function.getDefaultParamCount() > 0) {
parseContext.error(idToken.loc, "invalid parameter after default value parameters", idToken.string->c_str(), "");
return false;
}
TParameter param = { idToken.string, type, defaultValue };
function.addParameter(param); function.addParameter(param);
return true; return true;
......
...@@ -111,6 +111,7 @@ namespace glslang { ...@@ -111,6 +111,7 @@ namespace glslang {
bool acceptDefaultLabel(TIntermNode*&); bool acceptDefaultLabel(TIntermNode*&);
void acceptArraySpecifier(TArraySizes*&); void acceptArraySpecifier(TArraySizes*&);
void acceptPostDecls(TQualifier&); void acceptPostDecls(TQualifier&);
bool acceptDefaultParameterDeclaration(const TType&, TIntermTyped*&);
HlslParseContext& parseContext; // state of parsing and helper functions for building the intermediate HlslParseContext& parseContext; // state of parsing and helper functions for building the intermediate
TIntermediate& intermediate; // the final product, the intermediate representation, includes the AST TIntermediate& intermediate; // the final product, the intermediate representation, includes the AST
......
...@@ -1375,7 +1375,7 @@ TIntermNode* HlslParseContext::handleReturnValue(const TSourceLoc& loc, TIntermT ...@@ -1375,7 +1375,7 @@ TIntermNode* HlslParseContext::handleReturnValue(const TSourceLoc& loc, TIntermT
void HlslParseContext::handleFunctionArgument(TFunction* function, TIntermTyped*& arguments, TIntermTyped* newArg) void HlslParseContext::handleFunctionArgument(TFunction* function, TIntermTyped*& arguments, TIntermTyped* newArg)
{ {
TParameter param = { 0, new TType }; TParameter param = { 0, new TType, nullptr };
param.type->shallowCopy(newArg->getType()); param.type->shallowCopy(newArg->getType());
function->addParameter(param); function->addParameter(param);
if (arguments) if (arguments)
...@@ -2643,7 +2643,7 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& ...@@ -2643,7 +2643,7 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*&
// - user function // - user function
// - subroutine call (not implemented yet) // - subroutine call (not implemented yet)
// //
TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermNode* arguments) TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction* function, TIntermTyped* arguments)
{ {
TIntermTyped* result = nullptr; TIntermTyped* result = nullptr;
...@@ -2783,10 +2783,10 @@ TIntermTyped* HlslParseContext::handleLengthMethod(const TSourceLoc& loc, TFunct ...@@ -2783,10 +2783,10 @@ TIntermTyped* HlslParseContext::handleLengthMethod(const TSourceLoc& loc, TFunct
// //
// Add any needed implicit conversions for function-call arguments to input parameters. // Add any needed implicit conversions for function-call arguments to input parameters.
// //
void HlslParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) void HlslParseContext::addInputArgumentConversions(const TFunction& function, TIntermTyped*& arguments)
{ {
TIntermAggregate* aggregate = arguments->getAsAggregate(); TIntermAggregate* aggregate = arguments->getAsAggregate();
const auto setArg = [&](int argNum, TIntermNode* arg) { const auto setArg = [&](int argNum, TIntermTyped* arg) {
if (function.getParamCount() == 1) if (function.getParamCount() == 1)
arguments = arg; arguments = arg;
else { else {
...@@ -4483,8 +4483,8 @@ void HlslParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQuali ...@@ -4483,8 +4483,8 @@ void HlslParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQuali
// //
// Return the function symbol if found, otherwise nullptr. // Return the function symbol if found, otherwise nullptr.
// //
const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn, const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn,
TIntermNode* args) TIntermTyped*& args)
{ {
// const TFunction* function = nullptr; // const TFunction* function = nullptr;
...@@ -4583,6 +4583,22 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu ...@@ -4583,6 +4583,22 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
return false; return false;
} }
// Handle sampler betterness: An exact sampler match beats a non-exact match.
// (If we just looked at basic type, all EbtSamplers would look the same).
// If any type is not a sampler, just use the linearize function below.
if (from.getBasicType() == EbtSampler && to1.getBasicType() == EbtSampler && to2.getBasicType() == EbtSampler) {
// We can ignore the vector size in the comparison.
TSampler to1Sampler = to1.getSampler();
TSampler to2Sampler = to2.getSampler();
to1Sampler.vectorSize = to2Sampler.vectorSize = from.getSampler().vectorSize;
if (from.getSampler() == to2Sampler)
return from.getSampler() != to1Sampler;
if (from.getSampler() == to1Sampler)
return false;
}
// Might or might not be changing shape, which means basic type might // Might or might not be changing shape, which means basic type might
// or might not match, so within that, the question is how big a // or might not match, so within that, the question is how big a
// basic-type conversion is being done. // basic-type conversion is being done.
...@@ -4672,18 +4688,18 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu ...@@ -4672,18 +4688,18 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
// Handle aggregates: put all args into the new function call // Handle aggregates: put all args into the new function call
for (int arg=0; arg<int(args->getAsAggregate()->getSequence().size()); ++arg) { for (int arg=0; arg<int(args->getAsAggregate()->getSequence().size()); ++arg) {
// TODO: But for constness, we could avoid the new & shallowCopy, and use the pointer directly. // TODO: But for constness, we could avoid the new & shallowCopy, and use the pointer directly.
TParameter param = { 0, new TType }; TParameter param = { 0, new TType, nullptr };
param.type->shallowCopy(args->getAsAggregate()->getSequence()[arg]->getAsTyped()->getType()); param.type->shallowCopy(args->getAsAggregate()->getSequence()[arg]->getAsTyped()->getType());
convertedCall.addParameter(param); convertedCall.addParameter(param);
} }
} else if (args->getAsUnaryNode()) { } else if (args->getAsUnaryNode()) {
// Handle unaries: put all args into the new function call // Handle unaries: put all args into the new function call
TParameter param = { 0, new TType }; TParameter param = { 0, new TType, nullptr };
param.type->shallowCopy(args->getAsUnaryNode()->getOperand()->getAsTyped()->getType()); param.type->shallowCopy(args->getAsUnaryNode()->getOperand()->getAsTyped()->getType());
convertedCall.addParameter(param); convertedCall.addParameter(param);
} else if (args->getAsTyped()) { } else if (args->getAsTyped()) {
// Handle bare e.g, floats, not in an aggregate. // Handle bare e.g, floats, not in an aggregate.
TParameter param = { 0, new TType }; TParameter param = { 0, new TType, nullptr };
param.type->shallowCopy(args->getAsTyped()->getType()); param.type->shallowCopy(args->getAsTyped()->getType());
convertedCall.addParameter(param); convertedCall.addParameter(param);
} else { } else {
...@@ -4701,6 +4717,13 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu ...@@ -4701,6 +4717,13 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
if (tie) if (tie)
error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), ""); error(loc, "ambiguous best function under implicit type conversion", call.getName().c_str(), "");
// Append default parameter values if needed
if (!tie && bestMatch != nullptr) {
for (int defParam = call.getParamCount(); defParam < bestMatch->getParamCount(); ++defParam) {
handleFunctionArgument(&call, args, (*bestMatch)[defParam].defaultValue);
}
}
return bestMatch; return bestMatch;
} }
......
...@@ -79,12 +79,12 @@ public: ...@@ -79,12 +79,12 @@ public:
TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*); TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg); void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg);
TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right) const; TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right) const;
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*); TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*);
void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments); void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments); void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
void decomposeGeometryMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments); void decomposeGeometryMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*); TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
void addInputArgumentConversions(const TFunction&, TIntermNode*&); void addInputArgumentConversions(const TFunction&, TIntermTyped*&);
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermOperator&); TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermOperator&);
void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&); void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&);
TFunction* handleConstructorCall(const TSourceLoc&, const TType&); TFunction* handleConstructorCall(const TSourceLoc&, const TType&);
...@@ -126,7 +126,7 @@ public: ...@@ -126,7 +126,7 @@ public:
void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly); void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly);
void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&); void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&);
const TFunction* findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn, TIntermNode* args); const TFunction* findFunction(const TSourceLoc& loc, TFunction& call, bool& builtIn, TIntermTyped*& args);
void declareTypedef(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0); void declareTypedef(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0);
TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, TType&, TIntermTyped* initializer = 0); TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, TType&, TIntermTyped* initializer = 0);
void lengthenList(const TSourceLoc&, TIntermSequence& list, int size); void lengthenList(const TSourceLoc&, TIntermSequence& list, int size);
......
...@@ -586,7 +586,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c ...@@ -586,7 +586,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
{ "DeviceMemoryBarrier", nullptr, nullptr, "-", "-", EShLangPSCS }, { "DeviceMemoryBarrier", nullptr, nullptr, "-", "-", EShLangPSCS },
{ "DeviceMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangCS }, { "DeviceMemoryBarrierWithGroupSync", nullptr, nullptr, "-", "-", EShLangCS },
{ "distance", "S", "F", "V,", "F,", EShLangAll }, { "distance", "S", "F", "V,", "F,", EShLangAll },
{ "dot", "S", nullptr, "V,", "FI,", EShLangAll }, { "dot", "S", nullptr, "SV,", "FI,", EShLangAll },
{ "dst", nullptr, nullptr, "V4,", "F,", EShLangAll }, { "dst", nullptr, nullptr, "V4,", "F,", EShLangAll },
// { "errorf", "-", "-", "", "", EShLangAll }, TODO: varargs // { "errorf", "-", "-", "", "", EShLangAll }, TODO: varargs
{ "EvaluateAttributeAtCentroid", nullptr, nullptr, "SVM", "F", EShLangPS }, { "EvaluateAttributeAtCentroid", nullptr, nullptr, "SVM", "F", EShLangPS },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment