AzslcSemanticOrchestrator.cpp 101 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "AzslcSemanticOrchestrator.h"
  9. namespace AZ::ShaderCompiler
  10. {
  11. namespace // utility helpers to raise the abstraction level of SemanticOrchestrator's methods.
  12. {
  13. Packing::MatrixMajor ExtractMatrixMajorness(VarInfo& varInfo)
  14. {
  15. Packing::MatrixMajor major = Packing::MatrixMajor::Default;
  16. if (varInfo.CheckHasStorageFlag(StorageFlag::RowMajor))
  17. {
  18. major = Packing::MatrixMajor::RowMajor;
  19. }
  20. else if (varInfo.CheckHasStorageFlag(StorageFlag::ColumnMajor))
  21. {
  22. major = Packing::MatrixMajor::ColumnMajor;
  23. }
  24. return major;
  25. }
  26. TypeQualifier ExtractTypeQualifiers(azslParser::StorageFlagsContext* flags, vector<string>* unknownQualifiers = nullptr)
  27. {
  28. TypeQualifier qualifiers;
  29. for (auto* flagCtx : flags->storageFlag())
  30. {
  31. const auto& newFlag = AsFlag(flagCtx);
  32. qualifiers |= newFlag;
  33. if (newFlag == StorageFlag::Unknown && unknownQualifiers)
  34. {
  35. unknownQualifiers->push_back(flagCtx->getText());
  36. }
  37. }
  38. return qualifiers;
  39. }
  40. TypeQualifier ExtractTypeQualifiers(AstUnnamedVarDecl* ctx, vector<string>* unknownQualifiers = nullptr)
  41. {
  42. azslParser::StorageFlagsContext* flags = ExtractStorageFlagsFromVariableDeclarator(ctx);
  43. return flags ? ExtractTypeQualifiers(flags, unknownQualifiers) : TypeQualifier{};
  44. }
  45. }
  46. SemanticOrchestrator::SemanticOrchestrator(SymbolAggregator* sema, ScopeTracker* scope, azslLexer* lexer,
  47. PreprocessorLineDirectiveFinder* preprocessorLineDirectiveFinder /*= nullptr*/)
  48. : m_symbols{ sema },
  49. m_scope{ scope },
  50. m_lexer{ lexer },
  51. m_anonymousCounter{ 0 },
  52. m_preprocessorLineDirectiveFinder { preprocessorLineDirectiveFinder }
  53. {
  54. assert(sema != nullptr && scope != nullptr);
  55. }
  56. IdAndKind& SemanticOrchestrator::GetCurrentScopeIdAndKind()
  57. {
  58. auto nameOfScope = m_scope->GetNameOfCurScope();
  59. auto* idAndKindPtr = m_symbols->GetIdAndKindInfo(nameOfScope);
  60. if (!idAndKindPtr)
  61. {
  62. throw std::logic_error("Internal error: current scope not registered");
  63. }
  64. return *idAndKindPtr;
  65. }
  66. // Note that to factorize code between above and below, one could pass a runtime (or template integer), N-levels up as an argument.
  67. IdAndKind& SemanticOrchestrator::GetCurrentParentScopeIdAndKind()
  68. {
  69. auto nameOfParentScope = m_scope->GetNameOfCurParentScope();
  70. auto idAndKindPtr = m_symbols->GetIdAndKindInfo(nameOfParentScope);
  71. if (!idAndKindPtr)
  72. { // even parent scope will invariantly be registered. and the Levelup of '/' is '/'
  73. throw std::logic_error("Internal error: parent scope not registered");
  74. }
  75. return *idAndKindPtr;
  76. }
  77. // special high level entry of "RegisterFunction" feature but with pre-treatments related to scope resolution and semantic checks specifics to methods
  78. IdAndKind& SemanticOrchestrator::RegisterDeportedMethod(UnqualifiedNameView uqName, azslParser::UserDefinedTypeContext* className, AstFuncSig* ctx)
  79. {
  80. // extract the type name from the type rule. remember that it can be a reference to an existing UDT, or the inline definition of a new UDT.
  81. // note: in the latter case, the syntax is contrived but valid (surprising for C++/java people)
  82. // e.g. bool struct MyS{}::Method() {return true;}
  83. // however, the semantics of that expression are not supported. And that's because "struct MyS" is visited
  84. // AFTER the method registration, so MyS doesn't exist as a registered symbol yet.
  85. ExtractedComposedType extracted = ExtractComposedTypeNamesFromAstContext(className);
  86. verboseCout << ctx->start->getLine() << ": register method: " << className->getText() << "::" << uqName << "\n";
  87. // lookup for the symbol of the extracted scope
  88. IdAndKind* scopeIdKind = LookupSymbol(extracted.m_core.m_name);
  89. if (!scopeIdKind)
  90. {
  91. ThrowAzslcOrchestratorException(ORCHESTRATOR_SCOPE_NOT_FOUND,
  92. ctx->start, ConcatString("scope ", extracted.m_core.m_name,
  93. " for method ", uqName, " not found"));
  94. }
  95. auto [scopeUid, scopeKind] = *scopeIdKind;
  96. if (!scopeKind.IsKindOneOf(Kind::Class, Kind::ShaderResourceGroup))
  97. {
  98. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD_DEFINITION,
  99. ctx->start, "Only class and SRG may have deported method definitions");
  100. }
  101. IdentifierUID holdingScope = GetCurrentScopeIdAndKind().first;
  102. if (! (holdingScope.m_name == "/" || holdingScope == scopeUid))
  103. {
  104. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEFINITION_FOREIGN_SCOPE,
  105. ctx->start, ConcatString("definition of (", uqName,
  106. ") method of ", scopeUid.m_name, " in foreign scope ", holdingScope.m_name, " is forbidden"));
  107. }
  108. // between function name and the entrance into the function scope, the class scope is briefly activated.
  109. // this way, parameters may be specified as if in the scope of their holding function. e.g `ObjectOfCurrentScope MyClass::MyMethod(ObjectOfMyClass)`
  110. m_scope->EnterScope(scopeUid.GetName(), ctx->Name->getTokenIndex());
  111. // now that we're in scope, we can establish the decorated (leaf) identity of this function:
  112. auto decoratedUqName = UnqualifiedName{ConcatString(uqName, CreateDecorationOfFunction(ctx->functionParams()))};
  113. bool scopeIsClass = scopeKind.GetKind() == Kind::Class;
  114. // now let's check if that method was pre-declared in the class/SRG:
  115. optional<IdentifierUID> optionalIdentifier = scopeIsClass ? scopeKind.GetSubRefAs<ClassInfo>().FindMemberFromLeafName(decoratedUqName)
  116. : scopeKind.GetSubRefAs<SRGInfo>().FindMemberFromLeafName(decoratedUqName);
  117. // note that if the method is not found, we could accept to add it anyway to provide an extension-method feature a la C#.
  118. // it would be great to require an attribute or a keyword for that though (like [[extends]])
  119. // for now, it will be forbidden to inject methods in classes from outside.
  120. if (!optionalIdentifier)
  121. {
  122. ThrowAzslcOrchestratorException(ORCHESTRATOR_NO_DECLERATION, ctx->start,
  123. ConcatString((scopeIsClass ? "class " : "SRG "), scopeUid.m_name, " doesn't have a declaration for ", decoratedUqName));
  124. }
  125. // verify also the kind of the member
  126. auto* originalDeclarationAsFunc = m_symbols->GetAsSub<FunctionInfo>(*optionalIdentifier);
  127. if (!originalDeclarationAsFunc)
  128. {
  129. Kind realKindOfOriginallyDeclaredMember = m_symbols->GetIdAndKindInfo(optionalIdentifier->GetName())->second.GetKind();
  130. ThrowAzslcOrchestratorException(ORCHESTRATOR_UNEXPECTED_KIND,
  131. ctx->start, ConcatString((scopeIsClass ? "class " : "SRG "), scopeUid.m_name,
  132. " holds a member ", optionalIdentifier->m_name,
  133. " but it is of kind ", string{ Kind::ToStr(realKindOfOriginallyDeclaredMember) },
  134. " instead of expected ", string{ Kind::ToStr(Kind::Function) }));
  135. }
  136. // now we're good.
  137. // merge the type and the method name and call the classic register. RegisterFunction is going to re-run the decoration so just pass the naked name.
  138. string nakedJoined = JoinPath(scopeUid.GetName(), uqName, JoinPolicy::EmptyMeansRoot);
  139. return RegisterFunction(QualifiedNameView{nakedJoined}, ctx, AsFunc::Definition);
  140. }
  141. // unqualified-name (UQN) taking version. (expect a relative name to current scope)
  142. IdAndKind& SemanticOrchestrator::RegisterFunction(UnqualifiedNameView name, AstFuncSig* ctx, AsFunc statementGenre)
  143. {
  144. auto fqName = MakeFullyQualified(name);
  145. return RegisterFunction(fqName, ctx, statementGenre);
  146. }
  147. string SemanticOrchestrator::CreateDecorationOfFunction(azslParser::FunctionParamsContext* parametersContext) const
  148. {
  149. if (parametersContext == nullptr || parametersContext->Void())
  150. {
  151. return "()";
  152. }
  153. vector<QualifiedName> typeList;
  154. auto vectorOfFunctionParams = parametersContext->functionParam();
  155. typeList.reserve(vectorOfFunctionParams.size());
  156. // transform the collection into looked-up type names
  157. for (auto functionParamContext : vectorOfFunctionParams)
  158. {
  159. IdentifierUID paramType = LookupType(functionParamContext->type()); // [TODO-GFX][ATOM2627]: change this to CreateExtendedTypeInfo
  160. typeList.push_back(paramType.GetName());
  161. }
  162. return ::AZ::ShaderCompiler::CreateDecorationOfFunction(typeList.begin(), typeList.end());
  163. }
  164. QualifiedName SemanticOrchestrator::CreateDecoratedIdentityOfFunction(QualifiedNameView name, azslParser::FunctionParamsContext* parametersContext) const
  165. {
  166. return QualifiedName{ConcatString(name, CreateDecorationOfFunction(parametersContext))};
  167. }
  168. // qualified-name (FQN) taking version. (pre-resolved scope)
  169. IdAndKind& SemanticOrchestrator::RegisterFunction(QualifiedNameView fqUndecoratedName, AstFuncSig* ctx, AsFunc statementGenre)
  170. {
  171. // parameter validation: check the claim of the caller
  172. assert((statementGenre == AsFunc::Declaration && Is<azslParser::HlslFunctionDeclarationContext*>(ctx->parent))
  173. || (statementGenre == AsFunc::Definition && Is<azslParser::HlslFunctionDefinitionContext*>(ctx->parent)));
  174. auto line = ctx->Name->getLine();
  175. verboseCout << line << ": register func: " << fqUndecoratedName;
  176. // `/f` is undecorated. `/f(?int)` is decorated
  177. QualifiedName decoratedName = CreateDecoratedIdentityOfFunction(fqUndecoratedName, ctx->functionParams());
  178. verboseCout << " full identity: " << decoratedName << "\n";
  179. // validation
  180. bool isScopeCompositeType = IsScopeStructClassInterface();
  181. if (statementGenre == AsFunc::Declaration && ctx->ClassName)
  182. {
  183. if (isScopeCompositeType)
  184. {
  185. ThrowAzslcOrchestratorException(ORCHESTRATOR_OVERLY_QUALIFIED, ctx->Name,
  186. ConcatString(ctx->getText(), " is overly qualified. In-class declarations spawn new identifiers, and don't have to refer to existing symbols."));
  187. }
  188. else
  189. {
  190. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD, ctx->Name,
  191. ConcatString(ctx->getText(), "is a deported method declaration, which is considered ill-formed. You can make it a definition (with a body), or delete that statement."));
  192. }
  193. }
  194. IdAndKind* symbol = m_symbols->GetIdAndKindInfo(decoratedName);
  195. auto* funcInfo = symbol ? symbol->second.GetSubAs<FunctionInfo>() : nullptr;
  196. bool alreadyDeclared = !!symbol;
  197. bool alreadyDefined = funcInfo ? !!funcInfo->m_defNode : false;
  198. if (!alreadyDeclared) // brand new function
  199. {
  200. symbol = &m_symbols->AddIdentifier(decoratedName, Kind::Function, line);
  201. // prepare a virgin subinfo
  202. funcInfo = &symbol->second.GetSubAfterInitAs<Kind::Function>();
  203. }
  204. else
  205. {
  206. if (statementGenre == AsFunc::Declaration)
  207. {
  208. PrintWarning(Warn::W1, ctx->start, "ignored redundant redeclaration of function ", decoratedName,
  209. ", ", GetFirstSeenLineMessage(symbol->second));
  210. return *symbol;
  211. }
  212. auto originalKind = symbol->second.GetKind();
  213. if (originalKind != Kind::Function) // verify that we're not transforming a lychee into a melon
  214. {
  215. ThrowRedeclarationAsDifferentKind(decoratedName, Kind::Function, symbol->second, line);
  216. }
  217. if (alreadyDefined) // verify that it's not a second definition
  218. {
  219. ThrowAzslcOrchestratorException(ORCHESTRATOR_FUNCTION_ALREADY_DEFINED, ctx->Name,
  220. ConcatString("One Definition Rule: function ", symbol->first.m_name,
  221. " is already defined ", GetFirstSeenLineMessage(symbol->second)));
  222. }
  223. // this function was already declared before. (like a forward)
  224. // imagine this scenario:
  225. // void f(int i);
  226. //
  227. // void f(int num) {...}
  228. //
  229. // If we do nothing, the symbol table will have "f, f/i and f/num" but f/i will be unusable.
  230. // and worse, f will register two parameters i and num. (because by chance they have different names)
  231. // Also, recall that
  232. // void f(int);
  233. // Is a legal declaration, arguments don't need to be named, and the declarative functionality is still the same.
  234. // so for canonicalization we can consider that we never saw the arguments in declarations; but only as soon as we see a definition.
  235. // if we never store them, we won't be able to emit the declaration in the backend if it is the only thing we ever see.
  236. for (auto dependent : symbol->second.GetSubAs<FunctionInfo>()->GetParameters(true))
  237. { // delete AST-dependents (children) : the arguments.
  238. if (!dependent.m_varId.IsEmpty())
  239. {
  240. m_symbols->DeleteIdentifier(dependent.m_varId);
  241. }
  242. }
  243. // don't delete the old symbol because it has the seenat table, important to keep track of all occurrences of forward declarations.
  244. // just delete references to the deleted parameters.
  245. symbol->second.GetSubRefAs<FunctionInfo>().StashParameters();
  246. // also some attributes are only parsed at declaration, like override, or static.
  247. // and inversely, HLSL semantics are only considered at the definition site.
  248. // push a second apparition record in the ordered elastic symbol list
  249. // this way, the emitter can emit 2 entities: a declaration at first apparition, and the definition on the second apparition
  250. m_symbols->m_elastic.m_order.push_back(symbol->first);
  251. }
  252. // decompose the Id and Kind of this function
  253. auto& [newUID, newKind] = *symbol;
  254. // Add storage flags
  255. funcInfo->m_typeQualifier |= ExtractTypeQualifiers(ctx->storageFlags());
  256. CheckQualifersAreOnlyInlineOrStatic(funcInfo->m_typeQualifier, line); // throws a diagnostic if needed
  257. // keep track of original AST node
  258. if (statementGenre == AsFunc::Definition)
  259. {
  260. funcInfo->m_defNode = ctx;
  261. }
  262. if (!funcInfo->m_declNode)
  263. {
  264. funcInfo->m_declNode = ctx;
  265. }
  266. // OR fusion between decl and def sites
  267. funcInfo->m_mustOverride = funcInfo->m_mustOverride || ctx->Override() != nullptr;
  268. // return types must match (between redeclaration of this concrete function)
  269. ExtendedTypeInfo returnType = CreateExtendedTypeInfo(ctx->functionType(), {}, Packing::MatrixMajor::Default);
  270. if (alreadyDeclared && funcInfo->m_returnType != returnType)
  271. {
  272. ThrowAzslcOrchestratorException(ORCHESTRATOR_FUNCTION_INCONSISTENT_RETURN_TYPE, ctx->functionType()->start,
  273. ConcatString("function definition ", decoratedName, ", ",
  274. GetFirstSeenLineMessage(symbol->second), ", had a different return type: ",
  275. funcInfo->m_returnType.GetDisplayName(), ", versus now seen: ", returnType.GetDisplayName()));
  276. }
  277. funcInfo->m_returnType = returnType;
  278. assert(!funcInfo->m_returnType.IsEmpty());
  279. if (!funcInfo->m_returnType.IsClassFound())
  280. {
  281. PrintWarning(Warn::W2, ctx->functionType()->start, "return type ", ctx->functionType()->getText(), " not understood.",
  282. " (for function ", decoratedName, ")");
  283. }
  284. // try to fetch the overload-set:
  285. IdAndKind* overloadSetIdKind = m_symbols->GetIdAndKindInfo(fqUndecoratedName);
  286. OverloadSetInfo* overloadSet = overloadSetIdKind ? overloadSetIdKind->second.GetSubAs<OverloadSetInfo>() : nullptr;
  287. if (!overloadSetIdKind) // don't exist yet. it must be the first occurrence of this function's core name.
  288. {
  289. // create and prepare a brand new overload-set
  290. overloadSetIdKind = &m_symbols->AddIdentifier(fqUndecoratedName, Kind::OverloadSet, line);
  291. overloadSet = overloadSetIdKind->second.GetSubAs<OverloadSetInfo>();
  292. overloadSet->SetSetName(overloadSetIdKind->first); // set own id on it for logical independence (decoupling) in the methods of this object
  293. }
  294. // add this concrete function occurrence to the overload-set:
  295. overloadSet->PushConcreteFunction(newUID, returnType);
  296. // don't register the parameters here because of two reasons:
  297. // - the listener will naturally enter variableDeclarator rule which calls RegisterVar
  298. // - the scope needs to be the function scope, and we will enter the scope only after function registration
  299. if (isScopeCompositeType) // vocabulary reminder: composite-type = product or sum type = class/struct/union/interface/enum
  300. { // we are now in a class-kind scope -> so this function is a method
  301. funcInfo->m_isMethod = true;
  302. // access the class kindinfo and add a member:
  303. auto& classInfo = GetCurrentScopeSubInfoAs<ClassInfo>();
  304. classInfo.PushMember(newUID, Kind::Function);
  305. if (classInfo.m_kind == Kind::Interface)
  306. {
  307. funcInfo->m_isVirtual = true;
  308. }
  309. }
  310. else if (GetCurrentScopeIdAndKind().second.GetKind() == Kind::ShaderResourceGroup)
  311. {
  312. auto& srgInfo = GetCurrentScopeSubInfoAs<SRGInfo>();
  313. srgInfo.m_functions.push_back(newUID);
  314. }
  315. return *symbol;
  316. }
  317. IdAndKind& SemanticOrchestrator::RegisterFunctionDeclarationAndAddSeenat(UnqualifiedNameView uqName, AstFuncSig* signature)
  318. {
  319. // join scope and uqName (no unqualified lookup here, declarations are authoritative in scope):
  320. auto qName = MakeFullyQualified(uqName);
  321. // check existence, because re-declarations are innocent and should not take priority over ones higher up.
  322. // especially definition, which must be the winning occurrence for registration of identifiers.
  323. IdAndKind& symbol = RegisterFunction(uqName, signature, AsFunc::Declaration);
  324. // register a seenat to avoid missing redeclarations as references, because they don't trigger the idExpression rule.
  325. // (because a new declaration is always a direct Identifier lexer token)
  326. // a function's reference is incarnated by its name. like its call sites.
  327. auto location = MakeTokensLocation(signature->Name);
  328. RegisterSeenat(symbol, location);
  329. return symbol;
  330. }
  331. void SemanticOrchestrator::RegisterEnumerator(azslParser::EnumeratorDeclaratorContext* ctx)
  332. {
  333. auto* enumDefinitionCtx = As<azslParser::EnumDefinitionContext*>(ctx->parent->parent);
  334. bool isScopedEnum = Is<azslParser::ScopedEnumContext*>(enumDefinitionCtx->enumKey());
  335. UnqualifiedName parentName{(enumDefinitionCtx)->Name->getText()};
  336. QualifiedName enumQn;
  337. // reconstruct the identifier of the enumInfo (since current scope may or may not be it, we can't rely on it)
  338. if (isScopedEnum)
  339. {
  340. enumQn = GetCurrentScopeIdAndKind().first.m_name; // the current scope IS the enum
  341. assert(enumQn == QualifiedName{JoinPath(m_scope->GetNameOfCurParentScope(), parentName)}); // verify that we can reconstruct it
  342. }
  343. else
  344. {
  345. enumQn = MakeFullyQualified(parentName); // uses current scope (because the current scope encloses the enum)
  346. }
  347. auto& [enumId, parentKindInfo] = *m_symbols->GetIdAndKindInfo(enumQn);
  348. auto& enumInfo = parentKindInfo.GetSubRefAs<ClassInfo>();
  349. size_t line = ctx->Name->getLine();
  350. auto enumeratorName = UnqualifiedName{ctx->Name->getText()};
  351. auto& [uid, var] = AddIdentifier(enumeratorName, Kind::Variable, line);
  352. auto& varInfo = var.GetSubAfterInitAs<Kind::Variable>();
  353. if (ctx->Value)
  354. {
  355. varInfo.m_constVal = FoldEvalStaticConstExprNumericValue(ctx->Value);
  356. }
  357. varInfo.m_declNode = nullptr;
  358. varInfo.m_typeQualifier |= StorageFlag::Static;
  359. varInfo.m_typeQualifier |= StorageFlag::Const;
  360. varInfo.m_typeQualifier |= StorageFlag::Enumerator;
  361. varInfo.m_typeInfoExt = ExtendedTypeInfo{CreateTypeRefInfo(UnqualifiedNameView{enumQn}, OnNotFoundOrWrongKind::Diagnose),
  362. {}, {}, {}, Packing::MatrixMajor::Default };
  363. enumInfo.PushMember(uid, Kind::Variable);
  364. }
  365. void SemanticOrchestrator::RegisterSRGSemanticMember(AstSRGSemanticMemberDeclNode* ctx)
  366. {
  367. // access SRGSemanticInfo and add a member:
  368. auto& srgSemanticInfo = GetCurrentScopeSubInfoAs<ClassInfo>();
  369. if (ctx->Frequency && ctx->FrequencyValue)
  370. {
  371. if (auto* intLit = ctx->FrequencyValue->IntegerLiteral())
  372. {
  373. size_t line = ctx->Frequency->getLine();
  374. auto frequencyId = ctx->Frequency->getText();
  375. auto uqNameView = UnqualifiedNameView{ frequencyId };
  376. auto& [uid, var] = AddIdentifier(uqNameView, Kind::Variable, line);
  377. auto& varInfo = var.GetSubAfterInitAs<Kind::Variable>();
  378. varInfo.m_constVal = FoldEvalStaticConstExprNumericValue(intLit);
  379. varInfo.m_declNode = nullptr;
  380. varInfo.m_typeInfoExt = ExtendedTypeInfo{CreateTypeRefInfo(UnqualifiedNameView{"int"}, OnNotFoundOrWrongKind::Diagnose),
  381. {}, {}, {}, Packing::MatrixMajor::Default };
  382. srgSemanticInfo.PushMember(uid, Kind::Variable);
  383. }
  384. }
  385. else if (ctx->VariantFallback && ctx->VariantFallbackValue)
  386. {
  387. if (auto* intLit = ctx->VariantFallbackValue->IntegerLiteral())
  388. {
  389. size_t line = ctx->VariantFallback->getLine();
  390. auto variantFallback = ctx->VariantFallback->getText();
  391. auto uqNameView = UnqualifiedNameView{ variantFallback };
  392. auto& [uid, var] = AddIdentifier(uqNameView, Kind::Variable, line);
  393. auto& varInfo = var.GetSubAfterInitAs<Kind::Variable>();
  394. varInfo.m_constVal = FoldEvalStaticConstExprNumericValue(intLit);
  395. varInfo.m_declNode = nullptr;
  396. varInfo.m_typeInfoExt = ExtendedTypeInfo{CreateTypeRefInfo(UnqualifiedNameView{"int"}, OnNotFoundOrWrongKind::Diagnose),
  397. {}, {}, {}, Packing::MatrixMajor::Default };
  398. srgSemanticInfo.PushMember(uid, Kind::Variable);
  399. }
  400. }
  401. }
  402. IdAndKind& SemanticOrchestrator::RegisterTypeAlias(string_view newIdentifier, AstFuncType* existingTypeCtx, azslParser::TypeAliasingDefinitionStatementContext* ctx)
  403. {
  404. UnqualifiedNameView newId { newIdentifier };
  405. auto& idKind = AddIdentifier(newId, Kind::TypeAlias, ctx->start->getLine());
  406. auto& [uid, kinfo] = idKind;
  407. TypeAliasInfo& aliasInfo = kinfo.GetSubAfterInitAs<Kind::TypeAlias>();
  408. aliasInfo.m_declNode = ctx;
  409. aliasInfo.m_canonicalType = CreateExtendedTypeInfo(existingTypeCtx, {}, Packing::MatrixMajor::Default);
  410. if (!aliasInfo.m_canonicalType.IsClassFound())
  411. {
  412. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_TYPEALIAS_TARGET,
  413. existingTypeCtx->start,
  414. ConcatString("target type ", existingTypeCtx->getText() + " not understood in typealias expression"));
  415. }
  416. assert(aliasInfo.m_canonicalType.m_coreType.m_typeClass != TypeClass::Alias);
  417. // further registration in containing scopes
  418. auto& [curScopeId, curScopeKind] = GetCurrentScopeIdAndKind();
  419. if (curScopeKind.IsKindOneOf(Kind::Struct, Kind::Class))
  420. { // we are now in a struct/class-kind scope -> so this typealias is a member object.
  421. // access the class kindinfo and add a member:
  422. // future: check protocol validation with associatedtype
  423. auto& classInfo = GetCurrentScopeSubInfoAs<ClassInfo>();
  424. classInfo.PushMember(uid, Kind::TypeAlias);
  425. }
  426. return idKind;
  427. }
  428. IdAndKind& SemanticOrchestrator::RegisterSRGSemantic(AstSRGSemanticDeclNode* ctx)
  429. {
  430. return RegisterStructuredType(ctx, Kind::ShaderResourceGroupSemantic);
  431. }
  432. IdAndKind& SemanticOrchestrator::RegisterInterface(AstInterfaceDeclNode* ctx)
  433. {
  434. return RegisterStructuredType(ctx, Kind::Interface);
  435. }
  436. IdAndKind& SemanticOrchestrator::RegisterClass(AstClassDeclNode* ctx)
  437. {
  438. return RegisterStructuredType(ctx, Kind::Class);
  439. }
  440. IdAndKind& SemanticOrchestrator::RegisterStruct(AstStructDeclNode* ctx)
  441. {
  442. return RegisterStructuredType(ctx, Kind::Struct);
  443. }
  444. IdAndKind& SemanticOrchestrator::RegisterEnum(AstEnumDeclNode* ctx)
  445. {
  446. return RegisterStructuredType(ctx, Kind::Enum);
  447. }
  448. IdAndKind* SemanticOrchestrator::RegisterVar(Token* nameIdentifier, AstUnnamedVarDecl* ctx)
  449. {
  450. azslParser::FunctionParamContext* paramCtx = nullptr;
  451. auto typeCtx = ExtractTypeFromVariableDeclarator(ctx, &paramCtx);
  452. auto&& idText = nameIdentifier->getText();
  453. size_t line = nameIdentifier->getLine();
  454. const string verboseMessage = ConcatString(line, ": var decl: ", idText, "\n");
  455. verboseCout << verboseMessage;
  456. auto uqNameView = UnqualifiedNameView{idText};
  457. auto& varSymbol = AddIdentifier(uqNameView, Kind::Variable, line);
  458. auto& [uid, info] = varSymbol;
  459. // now fillup what we can about that variable in the IR:
  460. VarInfo& varInfo = info.GetSubRefAs<VarInfo>();
  461. // discover the storage flags:
  462. varInfo.m_typeQualifier = ExtractTypeQualifiers(ctx, &varInfo.m_unknownQualifiers);
  463. varInfo.m_declNode = ctx;
  464. varInfo.m_identifier = uqNameView;
  465. // discover array dimensions
  466. ArrayDimensions arrayDims;
  467. TryFoldArrayDimensions(ctx, arrayDims);
  468. // discover matrix majorness
  469. Packing::MatrixMajor major = ExtractMatrixMajorness(varInfo);
  470. // finally make the structure to hold all type information from the type context (will lookup/resolve type/typeof and compose the data)
  471. varInfo.m_typeInfoExt = CreateExtendedTypeInfo(typeCtx, arrayDims, major);
  472. assert(!varInfo.m_typeInfoExt.IsEmpty());
  473. if (!varInfo.m_typeInfoExt.IsClassFound())
  474. {
  475. PrintWarning(Warn::W2, typeCtx->start, "variable type ", typeCtx->getText(), " not understood.",
  476. " (for variable ", idText, ")");
  477. }
  478. if (varInfo.GetTypeRefInfo().IsInputAttachment(m_lexer))
  479. {
  480. if (!varInfo.GetGenericParameterTypeId().IsEmpty()
  481. && varInfo.GetGenericParameterTypeId().GetNameLeaf() != "float4")
  482. {
  483. PrintWarning(Warn::W1, typeCtx->start, typeCtx->getText(), " only float4 is supported on SubpassInput. Mutated to implicit float4 form.");
  484. }
  485. // erase the generic type, until the SubpassInputStub type can be templated:
  486. varInfo.m_typeInfoExt.m_genericParameter = TypeRefInfo{};
  487. m_subpassInputSeen = true;
  488. }
  489. // get enclosing scope:
  490. auto& [curScopeId, curScopeKind] = GetCurrentScopeIdAndKind();
  491. bool enclosedBySRG = curScopeKind.GetKind() == Kind::ShaderResourceGroup;
  492. assert(!curScopeKind.IsKindOneOf(Kind::Enum)); // should use RegisterEnumerator
  493. // Some semantic checks
  494. if (varInfo.CheckHasStorageFlag(StorageFlag::Inline))
  495. {
  496. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_INLINED_QUALIFIER, ctx->start,
  497. "inline qualification on variables is ill-formed");
  498. }
  499. bool global = curScopeId.GetName() == "/";
  500. bool isOption = varInfo.CheckHasStorageFlag(StorageFlag::Option);
  501. bool isRootconstant = varInfo.CheckHasStorageFlag(StorageFlag::Rootconstant);
  502. bool hasExplicitLocalFlag = varInfo.CheckHasAnyStorageFlags({ StorageFlag::Static, StorageFlag::Groupshared });
  503. if (isRootconstant || isOption)
  504. {
  505. if (arrayDims.IsArray())
  506. {
  507. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_NONGLOBAL_OPTION_OR_ROOTCONSTANT, ctx->start,
  508. "arrays can not be declared as rootconstants.");
  509. }
  510. if (!global)
  511. {
  512. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_NONGLOBAL_OPTION_OR_ROOTCONSTANT, ctx->start,
  513. "rootconstant or option qualifier is only accepted at top-level scope");
  514. }
  515. if (hasExplicitLocalFlag)
  516. {
  517. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_QUALIFIER_MIX, ctx->start,
  518. "static, groupshared qualifiers cannot be used with the rootconstant or option qualifier");
  519. }
  520. if (varInfo.CheckHasStorageFlag(StorageFlag::Const))
  521. {
  522. PrintWarning(Warn::W2, ctx->start, "const ignored in conjunction with rootconstant or option (because already immutable).");
  523. varInfo.m_typeQualifier &= StorageFlag::EnumType(~StorageFlag::Const);
  524. }
  525. }
  526. if (isOption)
  527. {
  528. // we'll set that here, an option is better flagged as static const for simplicity during emission
  529. varInfo.m_typeQualifier |= StorageFlag::Static;
  530. varInfo.m_typeQualifier |= StorageFlag::Const;
  531. // we don't do the same for rootconstant because they exist through a ConstantBuffer<STRUCT>
  532. }
  533. TypeClass typeClass = varInfo.GetTypeClass();
  534. if (typeClass == TypeClass::Sampler)
  535. {
  536. // let's extract any potential sampler information
  537. varInfo.m_samplerState = ExtractSamplerState(ctx->variableInitializer());
  538. // Emit a warning to the user in case we have upgraded the Sampler to ComparisonSampler implicitly
  539. bool declaredAsSamplerComparison = TypeIsSamplerComparisonState(ctx);
  540. if (varInfo.m_samplerState->m_isComparison && !declaredAsSamplerComparison)
  541. {
  542. PrintWarning(Warn::W3, ctx->start, "Comparison function found, sampler will be upgraded to SamplerComparisonState.\n",
  543. "Please use SamplerComparisonState if the use is intended, or remove the comparison function if not.");
  544. }
  545. varInfo.m_samplerState->m_isComparison |= declaredAsSamplerComparison;
  546. }
  547. if (ctx->packOffsetNode())
  548. {
  549. PrintWarning(Warn::W1, ctx->packOffsetNode()->start, "packoffset information ignored");
  550. }
  551. bool parentIsFuncDecl = IsParentRuleAFunctionDeclaration(paramCtx);
  552. bool parentIsFuncDef = IsParentRuleAFunctionDefinition(paramCtx);
  553. if (parentIsFuncDef || parentIsFuncDecl)
  554. {
  555. // We need to register each newly registered parameter variable ID, in the list of the function subinfo too:
  556. auto& funcSub = GetCurrentScopeSubInfoAs<FunctionInfo>();
  557. funcSub.PushParameter(uid, varInfo.m_typeInfoExt, varInfo.m_typeQualifier, varInfo.m_declNode->ArrayRankSpecifiers, ctx->variableInitializer());
  558. }
  559. bool isExtern = !varInfo.StorageFlagIsLocalLinkage(global || enclosedBySRG);
  560. bool dxilLibraryFlagType = typeClass == TypeClass::LibrarySubobject; // No need to check any semantic for subobjects. They just enrich the dxil metadata but don't participate in the program.
  561. if (isExtern && !dxilLibraryFlagType)
  562. {
  563. if (global && !varInfo.CheckHasStorageFlag(StorageFlag::Rootconstant))
  564. {
  565. ThrowAzslcOrchestratorException(ORCHESTRATOR_ILLEGAL_GLOBAL_VARIABLE, nameIdentifier,
  566. ConcatString(Decorate("'", idText), " extern global variables are ill-formed in AZSL. You might want an internal variable (static or groupshared), a rootconstant, an option, or to put your resource in a ShaderResourceGroup.") );
  567. }
  568. if (HasStandardInitializer(ctx))
  569. {
  570. ThrowAzslcOrchestratorException(ORCHESTRATOR_EXTERNAL_VARIABLE_WITH_INITIALIZER, nameIdentifier,
  571. ConcatString(Decorate("'", idText), " extern variables can't be initialized from the shader side, since their values are set by bindings.") );
  572. }
  573. }
  574. bool isStaticConst = varInfo.CheckHasAllStorageFlags({ StorageFlag::Static, StorageFlag::Const });
  575. if (curScopeKind.IsKindOneOf(Kind::Struct, Kind::Class))
  576. { // we are now in a struct/class-kind scope -> so this variable is a member object.
  577. // access the class kindinfo and add a member:
  578. auto& classInfo = GetCurrentScopeSubInfoAs<ClassInfo>();
  579. classInfo.PushMember(uid, Kind::Variable);
  580. if (HasStandardInitializer(ctx) && !isStaticConst)
  581. {
  582. ThrowAzslcOrchestratorException( ORCHESTRATOR_MEMBER_VARIABLE_WITH_INITIALIZER, nameIdentifier,
  583. ConcatString(idText, " default-member-initializers are not supported.") );
  584. }
  585. }
  586. if (curScopeKind.GetKind() == Kind::Interface)
  587. {
  588. // this is an impossible case because the parser doesn't accept these constructs.
  589. // but let's say one day we have an API that allows constructing AST programmatically.
  590. ThrowAzslcOrchestratorException(ORCHESTRATOR_ILLEGAL_MEMBER_VARIABLE_IN_INTERFACE,
  591. nameIdentifier, "member variables in interfaces are forbidden.");
  592. }
  593. if (enclosedBySRG)
  594. {
  595. FillOutSrgField(polymorphic_downcast<AstNamedVarDecl*>(ctx->parent), varInfo, uid, arrayDims);
  596. }
  597. // attempt some level of constant folding from initializers:
  598. // note to maintainers: do NOT try to avoid bloat in the verbose stream, by protecting this in `if (ctx->variableInitializer())`
  599. // it will result in the "static no-init-assignment zero initialization" case being <failed> instead of 0.
  600. varInfo.m_constVal = FoldEvalStaticConstExprNumericValue(varInfo);
  601. return &varSymbol;
  602. }
  603. void SemanticOrchestrator::RegisterNamelessFunctionParameter(azslParser::FunctionParamContext* ctx)
  604. {
  605. TypeQualifier typeQualifier = ExtractTypeQualifiers(ctx->storageFlags());
  606. CheckQualifersAreOnlyInlineOrStatic(typeQualifier, ctx->start->getLine()); // throws a diagnostic if needed
  607. ArrayDimensions arrayDims;
  608. TryFoldArrayDimensions(ctx->unnamedVariableDeclarator(), arrayDims);
  609. auto paramType = CreateExtendedTypeInfo(ctx->type(), arrayDims, Packing::MatrixMajor::Default);
  610. GetCurrentScopeSubInfoAs<FunctionInfo>().PushParameter({}, paramType, typeQualifier, ctx->unnamedVariableDeclarator()->ArrayRankSpecifiers, ctx->unnamedVariableDeclarator()->variableInitializer());
  611. }
  612. // Helper to avoid code redundancy for a message that is used in three different places.
  613. static string GetNonEasyToFoldMessage(const ArrayDimensions& arrayDims)
  614. {
  615. return ConcatString("array dimensions must be an easy-to-fold build time constant ( ",
  616. arrayDims.ToString(),
  617. " ) in external resource declaration");
  618. }
  619. void SemanticOrchestrator::FillOutSrgField(AstNamedVarDecl* ctx, VarInfo& varInfo, IdentifierUID varUid, ArrayDimensions& arrayDims)
  620. {
  621. const bool isUnboundedArray = arrayDims.IsUnbounded();
  622. if (!isUnboundedArray && !arrayDims.AreAllDimsFullyConstantFolded())
  623. {
  624. ThrowAzslcOrchestratorException(ORCHESTRATOR_ILLEGAL_FOLDABLE_ARRAY_DIMENSIONS, ctx->start
  625. , GetNonEasyToFoldMessage(arrayDims));
  626. }
  627. auto& [srgUid, srgKind] = GetCurrentScopeIdAndKind();
  628. auto& srgInfo = srgKind.GetSubRefAs<SRGInfo>();
  629. TypeClass typeClass = varInfo.GetTypeClass();
  630. assert(typeClass != TypeClass::Alias);
  631. string errorMessage;
  632. if (!m_unboundedArraysValidator.CheckFieldCanBeAddedToSrg(isUnboundedArray, srgUid, srgInfo, varUid, varInfo, typeClass, &errorMessage))
  633. {
  634. ThrowAzslcOrchestratorException(ORCHESTRATOR_UNBOUNDED_RESOURCE_ISSUE, ctx->start, errorMessage);
  635. }
  636. if (typeClass == TypeClass::ConstantBuffer)
  637. {
  638. srgInfo.m_CBs.push_back(varUid);
  639. }
  640. else if (typeClass == TypeClass::Sampler)
  641. {
  642. srgInfo.m_samplers.push_back(varUid);
  643. }
  644. else if (IsViewType(typeClass))
  645. {
  646. srgInfo.m_srViews.push_back(varUid);
  647. }
  648. else if (!varInfo.StorageFlagIsLocalLinkage(true))
  649. {
  650. if (isUnboundedArray)
  651. {
  652. ThrowAzslcOrchestratorException(ORCHESTRATOR_ILLEGAL_FOLDABLE_ARRAY_DIMENSIONS, ctx->start
  653. , GetNonEasyToFoldMessage(arrayDims));
  654. }
  655. if (!varInfo.GetTypeRefInfo().IsPackable())
  656. {
  657. ThrowAzslcOrchestratorException(ORCHESTRATOR_NON_PACKABLE_TYPE_IN_SRG_CONSTANT, ctx->start,
  658. ConcatString(varInfo.GetTypeId().m_name,
  659. " is of kind ",
  660. TypeClass::ToStr(varInfo.GetTypeClass()),
  661. " which is a non packable kind of type."));
  662. }
  663. auto& classInfo = srgInfo.m_implicitStruct;
  664. classInfo.PushMember(varUid, Kind::Variable);
  665. }
  666. else
  667. {
  668. if (isUnboundedArray)
  669. {
  670. ThrowAzslcOrchestratorException(ORCHESTRATOR_ILLEGAL_FOLDABLE_ARRAY_DIMENSIONS, ctx->start
  671. , GetNonEasyToFoldMessage(arrayDims));
  672. }
  673. assert(varInfo.StorageFlagIsLocalLinkage(true));
  674. srgInfo.m_nonexternVariables.push_back(varUid);
  675. }
  676. varInfo.m_srgMember = true;
  677. }
  678. SamplerStateDesc SemanticOrchestrator::ExtractSamplerState(AstVarInitializer* ctx)
  679. {
  680. if (ctx == nullptr || ctx->standardVariableInitializer())
  681. {
  682. SamplerStateDesc defaultState;
  683. defaultState.m_isDynamic = true; // no initializer, or variable assignation both denotes a dynamic sampler.
  684. return defaultState;
  685. }
  686. // Antlr auto-generates tons of methods for every rule, so we have to walk and parse them here.
  687. // We declare a couple of helper methods to simplify the rest of the resolve function:
  688. auto GetAddressMode = [](azslParser::AddressModeEnumContext* ctx) -> SamplerStateDesc::AddressMode
  689. {
  690. return ctx->ADDRESS_MODE_WRAP() ? SamplerStateDesc::AddressMode::Wrap
  691. : ctx->ADDRESS_MODE_CLAMP() ? SamplerStateDesc::AddressMode::Clamp
  692. : ctx->ADDRESS_MODE_MIRROR() ? SamplerStateDesc::AddressMode::Mirror
  693. : ctx->ADDRESS_MODE_BORDER() ? SamplerStateDesc::AddressMode::Border
  694. : SamplerStateDesc::AddressMode::MirrorOnce;
  695. };
  696. auto GetCompFunc = [](azslParser::ComparisonFunctionEnumContext* ctx) -> SamplerStateDesc::ComparisonFunc
  697. {
  698. return ctx->COMPARISON_FUNCTION_NEVER() ? SamplerStateDesc::ComparisonFunc::Never
  699. : ctx->COMPARISON_FUNCTION_NEVER() ? SamplerStateDesc::ComparisonFunc::Never
  700. : ctx->COMPARISON_FUNCTION_LESS() ? SamplerStateDesc::ComparisonFunc::Less
  701. : ctx->COMPARISON_FUNCTION_EQUAL() ? SamplerStateDesc::ComparisonFunc::Equal
  702. : ctx->COMPARISON_FUNCTION_LESS_EQUAL() ? SamplerStateDesc::ComparisonFunc::LessEqual
  703. : ctx->COMPARISON_FUNCTION_GREATER() ? SamplerStateDesc::ComparisonFunc::Greater
  704. : ctx->COMPARISON_FUNCTION_NOT_EQUAL() ? SamplerStateDesc::ComparisonFunc::NotEqual
  705. : ctx->COMPARISON_FUNCTION_GREATER_EQUAL() ? SamplerStateDesc::ComparisonFunc::GreaterEqual
  706. : SamplerStateDesc::ComparisonFunc::Always;
  707. };
  708. auto GetRedcType = [](azslParser::ReductionTypeEnumContext* ctx) -> SamplerStateDesc::ReductionType
  709. {
  710. return ctx->REDUCTION_TYPE_FILTER() ? SamplerStateDesc::ReductionType::Filter
  711. : ctx->REDUCTION_TYPE_COMPARISON() ? SamplerStateDesc::ReductionType::Comparison
  712. : ctx->REDUCTION_TYPE_MINIMUM() ? SamplerStateDesc::ReductionType::Minimum
  713. : SamplerStateDesc::ReductionType::Maximum;
  714. };
  715. auto GetFilterType = [](azslParser::FilterModeEnumContext* ctx) -> SamplerStateDesc::FilterMode
  716. {
  717. return ctx->FILTER_MODE_LINEAR() ? SamplerStateDesc::FilterMode::Linear : SamplerStateDesc::FilterMode::Point;
  718. };
  719. auto GetBorderColor = [](azslParser::BorderColorEnumContext* ctx) -> SamplerStateDesc::BorderColor
  720. {
  721. return ctx->BORDER_COLOR_OPAQUE_BLACK() ? SamplerStateDesc::BorderColor::OpaqueBlack
  722. : ctx->BORDER_COLOR_TRANSPARENT_BLACK() ? SamplerStateDesc::BorderColor::TransparentBlack
  723. : SamplerStateDesc::BorderColor::OpaqueWhite;
  724. };
  725. // Now proceed with resolving the sampler state
  726. SamplerStateDesc desc;
  727. auto samplerOpts = ctx->samplerBodyDeclaration()->samplerMemberDeclaration();
  728. for (auto samplerOption : samplerOpts)
  729. {
  730. if (auto opt = samplerOption->maxAnisotropyOption())
  731. {
  732. auto maxAnisoVal = FoldEvalStaticConstExprNumericValue(opt->IntegerLiteral());
  733. desc.m_anisotropyMax = static_cast<uint32_t>(ExtractValueAsInt64(maxAnisoVal));
  734. desc.m_anisotropyEnable = true;
  735. }
  736. else if (auto opt = samplerOption->minLodOption())
  737. {
  738. auto minLODVal = FoldEvalStaticConstExprNumericValue(opt->FloatLiteral(), false);
  739. desc.m_mipLodMin = ExtractValueAsFloat(minLODVal);
  740. }
  741. else if (auto opt = samplerOption->maxLodOption())
  742. {
  743. auto maxLODVal = FoldEvalStaticConstExprNumericValue(opt->FloatLiteral(), false);
  744. desc.m_mipLodMax = ExtractValueAsFloat(maxLODVal);
  745. }
  746. else if (auto opt = samplerOption->mipLodBiasOption())
  747. {
  748. auto biasVal = FoldEvalStaticConstExprNumericValue(opt->FloatLiteral(), false);
  749. desc.m_mipLodBias = ExtractValueAsFloat(biasVal);
  750. }
  751. else if (auto opt = samplerOption->minFilterOption())
  752. {
  753. desc.m_filterMin = GetFilterType(opt->filterModeEnum());
  754. }
  755. else if (auto opt = samplerOption->magFilterOption())
  756. {
  757. desc.m_filterMag = GetFilterType(opt->filterModeEnum());
  758. }
  759. else if (auto opt = samplerOption->mipFilterOption())
  760. {
  761. desc.m_filterMip = GetFilterType(opt->filterModeEnum());
  762. }
  763. else if (auto opt = samplerOption->reductionTypeOption())
  764. {
  765. desc.m_reductionType = GetRedcType(opt->reductionTypeEnum());
  766. }
  767. else if (auto opt = samplerOption->comparisonFunctionOption())
  768. {
  769. desc.m_comparisonFunc = GetCompFunc(opt->comparisonFunctionEnum());
  770. desc.m_isComparison = true;
  771. }
  772. else if (auto opt = samplerOption->addressUOption())
  773. {
  774. desc.m_addressU = GetAddressMode(opt->addressModeEnum());
  775. }
  776. else if (auto opt = samplerOption->addressVOption())
  777. {
  778. desc.m_addressV = GetAddressMode(opt->addressModeEnum());
  779. }
  780. else if (auto opt = samplerOption->addressWOption())
  781. {
  782. desc.m_addressW = GetAddressMode(opt->addressModeEnum());
  783. }
  784. else if (auto opt = samplerOption->borderColorOption())
  785. {
  786. desc.m_borderColor = GetBorderColor(opt->borderColorEnum());
  787. }
  788. }
  789. return desc;
  790. }
  791. IdAndKind& SemanticOrchestrator::RegisterSRG(AstSRGDeclNode* ctx)
  792. {
  793. auto const& idText = ctx->Name->getText();
  794. size_t line = ctx->Name->getLine();
  795. verboseCout << line << ": srg decl: " << idText << "\n";
  796. auto uqNameView = UnqualifiedNameView{ idText };
  797. IdAndKind* srgSym = LookupSymbol(uqNameView);
  798. if (srgSym) // already exists
  799. {
  800. if (ctx->Partial()) // case of a syntactically valid extension
  801. {
  802. SRGInfo& srgInfo = srgSym->second.GetSubRefAs<SRGInfo>();
  803. if (!srgInfo.IsPartial())
  804. {
  805. ThrowAzslcOrchestratorException(ORCHESTRATOR_TRYING_TO_EXTEND_NOT_PARTIAL_SRG,
  806. ctx->Partial()->getSymbol(), ConcatString("Cannot extend ShaderResourceGroup ", uqNameView, " ",
  807. GetFirstSeenLineMessage(srgSym->second),
  808. " because its original declaration isn't 'partial'"));
  809. }
  810. return *srgSym; // valid: both original and current SRG declaration statements carry partial.
  811. }
  812. ThrowAzslcOrchestratorException(ORCHESTRATOR_ODR_VIOLATION,
  813. ctx->Name, ConcatString("ShaderResourceGroup ", uqNameView, " already exists, ", GetFirstSeenLineMessage(srgSym->second),
  814. ". Consider using the 'partial' keyword (on both declaration sites) to extend a ShaderResourceGroup."));
  815. }
  816. if (!ctx->Partial() && !ctx->Semantic)
  817. {
  818. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_SEMANTIC_DECLARATION,
  819. ctx->Name, "A semantic is mandatory on the declaration of a non-partial ShaderResourceGroup.");
  820. }
  821. auto& symbol = AddIdentifier(uqNameView, Kind::ShaderResourceGroup, line);
  822. // now fillup what we can about the kindinfo:
  823. auto& [uid, info] = symbol;
  824. SRGInfo& srgInfo = info.GetSubAfterInitAs<Kind::ShaderResourceGroup>();
  825. srgInfo.m_declNode = ctx;
  826. srgInfo.m_implicitStruct.m_kind = Kind::Struct;
  827. return symbol;
  828. }
  829. void SemanticOrchestrator::RegisterBases(azslParser::BaseListContext* ctx)
  830. {
  831. using namespace std::string_literals;
  832. for (auto& idexpr : ctx->idExpression())
  833. {
  834. UnqualifiedName baseName = ExtractNameFromIdExpression(idexpr);
  835. auto baseSymbol = LookupSymbol(baseName);
  836. if (!baseSymbol)
  837. {
  838. ThrowAzslcOrchestratorException(ORCHESTRATOR_UNSPECIFIED_BASE_SYMBOL,
  839. ctx->start, ConcatString("Base symbol "s, baseName, " not found"));
  840. }
  841. auto& curClassInfo = GetCurrentScopeSubInfoAs<ClassInfo>();
  842. curClassInfo.m_bases.emplace(baseSymbol->first);
  843. }
  844. }
  845. void SemanticOrchestrator::RegisterSeenat(IdAndKind& idPair, const TokensLocation& location)
  846. {
  847. auto& [uid, info] = idPair;
  848. Seenat seenat;
  849. seenat.m_referredDefinition = uid;
  850. seenat.m_where = location;
  851. info.GetSeenats().emplace_back(seenat);
  852. const string verboseMessage = ConcatString(seenat.m_where.m_line, ": seenat registered for ", uid.m_name, " at col ", seenat.m_where.m_charPos + 1, "\n");
  853. verboseCout << verboseMessage;
  854. }
  855. void SemanticOrchestrator::RegisterSeenat(AstIdExpr* ctx)
  856. {
  857. RegisterSeenat(ctx, GetCurrentScopeIdAndKind().first.GetName());
  858. }
  859. // e.g. provided "int a; X GetX(int);" then from expression "(a, GetX(2), true)" MangleArgumentList returns "(?int,/X,?bool)"
  860. string SemanticOrchestrator::MangleArgumentList(azslParser::ArgumentListContext* ctx) const
  861. {
  862. // resolve all argument types.
  863. vector<QualifiedName> resolvedArguments;
  864. auto vectorOfExpressions = ctx->arguments() ? ctx->arguments()->expression() : vector<AstExpr*>{};
  865. resolvedArguments.reserve(vectorOfExpressions.size());
  866. for (AstExpr* expression : vectorOfExpressions)
  867. {
  868. QualifiedName typeName = TypeofExpr(expression);
  869. resolvedArguments.push_back(typeName);
  870. }
  871. return ::AZ::ShaderCompiler::CreateDecorationOfFunction(resolvedArguments.begin(), resolvedArguments.end());
  872. }
  873. bool SemanticOrchestrator::HasAnyDefaultParameterValue(const IdentifierUID& functionUid) const
  874. {
  875. auto* funcInfo = m_symbols->GetAsSub<FunctionInfo>(functionUid);
  876. return funcInfo ? funcInfo->HasAnyDefaultParameterValue() : false;
  877. }
  878. void SemanticOrchestrator::OverrideAzslcExceptionFileAndLine(size_t azslLineNumber) const
  879. {
  880. if (!m_preprocessorLineDirectiveFinder)
  881. {
  882. return;
  883. }
  884. const LineDirectiveInfo* lineInfo = m_preprocessorLineDirectiveFinder->GetNearestPreprocessorLineDirective(azslLineNumber);
  885. if (!lineInfo)
  886. {
  887. return;
  888. }
  889. AzslcException::s_currentSourceFileName = lineInfo->m_containingFilename;
  890. AzslcException::s_sourceFileLineNumber = m_preprocessorLineDirectiveFinder->GetLineNumberInOriginalSourceFile(*lineInfo, azslLineNumber);
  891. }
  892. IdAndKind* SemanticOrchestrator::ResolveOverload(IdAndKind* maybeOverloadSet, azslParser::ArgumentListContext* argumentListCtx) const
  893. {
  894. IdAndKind* toReturn = maybeOverloadSet;
  895. if (maybeOverloadSet && maybeOverloadSet->second.GetKind() == Kind::OverloadSet)
  896. {
  897. string mangledArgList = argumentListCtx ? MangleArgumentList(argumentListCtx) : "";
  898. auto& setInfo = maybeOverloadSet->second.GetSubRefAs<OverloadSetInfo>();
  899. // attempt direct matching or arity matching
  900. IdentifierUID concrete = setInfo.GetConcreteFunctionThatMatchesArgumentList(mangledArgList);
  901. if (concrete.IsEmpty()) // failure case
  902. {
  903. std::stringstream message;
  904. message << " unable to match arguments " << mangledArgList << " to a registered overload. candidates are:\n";
  905. setInfo.ForEach([&](auto&& uid){ message << uid.GetName() << "\n"; });
  906. if (setInfo.HasHomogeneousReturnType())
  907. {
  908. verboseCout << (argumentListCtx ? std::to_string(argumentListCtx->start->getLine()) : "")
  909. << message.str() << " It is not an error since that overload-set has homogeneous return type\n"; // at this point of the source. further declaration can change that.
  910. }
  911. else
  912. {
  913. ThrowAzslcOrchestratorException(ORCHESTRATOR_OVERLOAD_RESOLUTION_HARD_FAILURE, argumentListCtx ? argumentListCtx->start : nullptr,
  914. ConcatString(message.str(), " This is an error because functions belonging to this overload-set have heterogeneous return types.\n",
  915. "Consider using type-casts to help type resolution."));
  916. }
  917. }
  918. else
  919. {
  920. toReturn = m_symbols->GetIdAndKindInfo(concrete.GetName());
  921. }
  922. }
  923. return toReturn;
  924. }
  925. void SemanticOrchestrator::RegisterSeenat(AstIdExpr* ctx, QualifiedNameView startupScope)
  926. {
  927. auto* argumentList = GetArgumentListIfBelongsToFunctionCall(ctx); // no need to execute that in the loop body, extracted up-here.
  928. // an id-expression is made of nested parts: stuff::thing::leaf
  929. // for each part we need to register a reference to the symbol the nested name refers to.
  930. // so we loop over the expression, reconstructing by appending part by part so correctly qualify each nested part for lookup.
  931. // the startupScope is not the first path of the path of each element, but the CONTEXT from which we start the lookup.
  932. // the lookup mechanism must sill execute. Just not necessarily from the current scope as startup context.
  933. string partialExpression;
  934. ForEachIdExpressionPart(ctx, [&](const IdExpressionPart& part)
  935. { // this is not Schlemiel the painter
  936. partialExpression += part.GetAZIRMangledText();
  937. if (!part.IsScopeToken()) // scope token is the SRO "::"
  938. {
  939. auto* idToKind = ResolveOverload(m_symbols->LookupSymbol(startupScope, UnqualifiedNameView{partialExpression}),
  940. argumentList);
  941. if (idToKind)
  942. {
  943. auto tl = MakeTokensLocation(ctx, part.m_token);
  944. RegisterSeenat(*idToKind, tl);
  945. }
  946. else
  947. {
  948. DiagnoseUndeclaredSub(ctx->start, startupScope, partialExpression);
  949. }
  950. }
  951. });
  952. }
  953. void SemanticOrchestrator::DiagnoseUndeclaredSub(Token* atToken, QualifiedNameView startupScope, string partialName) const
  954. {
  955. // check if we can help the user a bit, that will avoid long pondering when DXC refuses to build something that broke through translation.
  956. auto parent = GetParentName(partialName);
  957. bool hasParent = !parent.empty();
  958. // try to get the parent to see if we can say something special.
  959. auto* idToKind = m_symbols->LookupSymbol(startupScope, UnqualifiedNameView{parent});
  960. bool parentFound = hasParent && idToKind != nullptr;
  961. if (parentFound)
  962. {
  963. auto& [id, kind] = *idToKind;
  964. if (kind.GetKind() == Kind::Enum)
  965. {
  966. bool isScopedEnum = kind.GetSubRefAs<ClassInfo>().Get<EnumerationInfo>()->m_isScoped;
  967. if (!isScopedEnum)
  968. {
  969. PrintWarning(Warn::W1, atToken, "in AZSL, non-class enumeration ", parent, " can't qualify names.");
  970. return; // job done
  971. }
  972. }
  973. PrintWarning(Warn::W3, atToken, "undeclared sub-symbol in idexpression: ", parent, " was found, but not ", partialName);
  974. }
  975. else
  976. { // that warning is probably going to fire a tad too much. repeated for all left-over elements on the right of an expression that failed early.
  977. // eg i_did_a_typo_here_omg::not_found::not_found::not_found... you see the point.
  978. // but being here is our only chance to grab lone identifiers (completely unqualified).
  979. // so protect it for only that case.
  980. if (!hasParent)
  981. {
  982. PrintWarning(Warn::W3, atToken, "undeclared sub-symbol in idexpression: ", partialName);
  983. }
  984. }
  985. }
  986. pair<bool, QualifiedName> SemanticOrchestrator::VerifyLHSExprOfMAExprIsValid(azslParser::MemberAccessExpressionContext* ctx) const
  987. {
  988. return VerifyTypeIsScopeComposable(ctx->LHSExpr);
  989. }
  990. //! Member Access Expression (MAE) such as A.B is a scoped lookup. (A is the scope and B is the composition)
  991. //! Typeof Expression such as typeof(A)::B is a scoped lookup. (typeof(A) is the scope and B is the composition)
  992. //! returns the looked up scope
  993. pair<bool, QualifiedName> SemanticOrchestrator::VerifyTypeIsScopeComposable(azslParser::ExpressionContext* typeScopeAnyExpression) const
  994. {
  995. return VerifyTypeIsScopeComposable(TypeofExpr(typeScopeAnyExpression), typeScopeAnyExpression->getText(), typeScopeAnyExpression->start->getLine());
  996. }
  997. //! same function as above for already resolved typeof
  998. pair<bool, QualifiedName> SemanticOrchestrator::VerifyTypeIsScopeComposable(QualifiedNameView lhsTypeName, optional<string> lhsExpressionText/*= none*/, optional<size_t> line/*= none*/) const
  999. {
  1000. // (generalized) member-access-expressions can only work on types with members:
  1001. // any UDT: struct, enum, class, interface. Any scope; srg, function. Any type-like: typeof, typedef (because they get collapsed)
  1002. auto lhsSymbol = m_symbols->GetIdAndKindInfo(lhsTypeName);
  1003. bool valid = true;
  1004. if (!lhsSymbol)
  1005. {
  1006. PrintWarning(Warn::W2, line, "unresolved member access ",
  1007. "on undeclared type ", lhsTypeName,
  1008. (lhsExpressionText ? " (of expression " + *lhsExpressionText + ")" : ""), ")");
  1009. valid = false;
  1010. }
  1011. else // left side symbol exists
  1012. {
  1013. const KindInfo& lhsKindInfo = lhsSymbol->second;
  1014. if (!lhsKindInfo.IsKindOneOf(Kind::Namespace, Kind::Class, Kind::Struct, Kind::Enum, Kind::Interface, Kind::ShaderResourceGroup, Kind::Function))
  1015. {
  1016. auto outputStream = lhsKindInfo.GetKind() == Kind::Type ? verboseCout : warningCout;
  1017. // registered predefined types can have members, but we don't know them -> not important. But anything else is very likely an ill-formed source.
  1018. PrintWarning(outputStream, Warn::W1, line, none, " warning: ill-formed semantics: access of member ",
  1019. " on an unsupported kind ", Kind::ToStr(lhsKindInfo.GetKind()),
  1020. " (of believed type ", lhsSymbol->first.GetName(),
  1021. (lhsExpressionText ? " from expression " + *lhsExpressionText : ""), ")");
  1022. valid = false;
  1023. }
  1024. }
  1025. return {valid, lhsTypeName};
  1026. }
  1027. QualifiedName SemanticOrchestrator::ComposeMemberNameWithScopeAndGetType(QualifiedName scopingType, AstIdExpr* rhsMember) const
  1028. {
  1029. // get the symbol name we want to lookup on the right hand side:
  1030. UnqualifiedName rhsName = ExtractNameFromIdExpression(rhsMember);
  1031. // look it up from the scope of the lhs's type: (this behavior is explained in https://stackoverflow.com/questions/56253767)
  1032. auto fullyResolved = m_symbols->LookupSymbol(scopingType, rhsName);
  1033. if (!fullyResolved)
  1034. {
  1035. PrintWarning(Warn::W3, rhsMember->start, "type tracking fail: ", rhsName, " is not a member of ", scopingType);
  1036. }
  1037. else // rhs symbol exists
  1038. { // let's extract its type and return that.
  1039. return GetTypeName(fullyResolved);
  1040. }
  1041. return {"<fail>"};
  1042. }
  1043. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::ExpressionContext* ctx) const
  1044. {
  1045. try
  1046. {
  1047. return VisitFirstNonNull([this](auto* ctx) { return TypeofExpr(ctx); },
  1048. As<AstIdExpr*>(ctx),
  1049. As<azslParser::IdentifierExpressionContext*>(ctx),
  1050. As<azslParser::ParenthesizedExpressionContext*>(ctx),
  1051. As<azslParser::CastExpressionContext*>(ctx),
  1052. As<azslParser::MemberAccessExpressionContext*>(ctx),
  1053. As<azslParser::FunctionCallExpressionContext*>(ctx),
  1054. As<azslParser::ArrayAccessExpressionContext*>(ctx),
  1055. As<azslParser::ConditionalExpressionContext*>(ctx),
  1056. As<azslParser::AssignmentExpressionContext*>(ctx),
  1057. As<azslParser::NumericConstructorExpressionContext*>(ctx),
  1058. As<azslParser::LiteralExpressionContext*>(ctx),
  1059. As<azslParser::LiteralContext*>(ctx));
  1060. }
  1061. catch (AllNull&)
  1062. {
  1063. verboseCout << ctx->start->getLine() << ": unsupported expression in typeof: " << typeid(ctx).name() << "\n";
  1064. return {"<fail>"};
  1065. }
  1066. }
  1067. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::ExpressionExtContext* ctx) const
  1068. {
  1069. return VisitFirstNonNull([this](auto* ctx) { return TypeofExpr(ctx); },
  1070. As<azslParser::OtherExpressionContext*>(ctx),
  1071. As<azslParser::CommaExpressionContext*>(ctx));
  1072. }
  1073. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::OtherExpressionContext* ctx) const
  1074. {
  1075. return TypeofExpr(ctx->Expr);
  1076. }
  1077. QualifiedName SemanticOrchestrator::TypeofExpr(AstType* ctx) const
  1078. {
  1079. return LookupType(ctx).GetName();
  1080. }
  1081. QualifiedName SemanticOrchestrator::TypeofExpr(AstFuncType* ctx) const
  1082. {
  1083. return LookupType(ctx).GetName();
  1084. }
  1085. QualifiedName SemanticOrchestrator::TypeofExpr(AstIdExpr* ctx) const
  1086. {
  1087. // idExpression will represent registered symbol. if not, it's a fail.
  1088. UnqualifiedName uqName = ExtractNameFromIdExpression(ctx);
  1089. auto lookup = ResolveOverload(LookupSymbol(uqName), GetArgumentListIfBelongsToFunctionCall(ctx));
  1090. if (!lookup)
  1091. {
  1092. verboseCout << ctx->start->getLine() << ": can't find typeof " << uqName << "\n";
  1093. return {"<fail>"};
  1094. }
  1095. else
  1096. {
  1097. return GetTypeName(lookup); // this call is often the leaf of the TypeofExpr call tree.
  1098. }
  1099. }
  1100. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::IdentifierExpressionContext* ctx) const
  1101. {
  1102. return TypeofExpr(ctx->idExpression());
  1103. }
  1104. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::MemberAccessExpressionContext* ctx) const
  1105. {
  1106. // "LHS.RHS"
  1107. // typeof(LHS.RHS) is the type of RHS
  1108. // start with a simple case -> rhs is absolute (e.g. "stuff.::A::f()" ::A::f is absolute)
  1109. bool rhsIsAbsolute = ctx->Member->qualifiedId() && ctx->Member->qualifiedId()->nestedNameSpecifier()->GlobalSROToken;
  1110. if (rhsIsAbsolute)
  1111. {
  1112. return TypeofExpr(ctx->Member /*idExpression*/);
  1113. }
  1114. // otherwise, RHS is relative to LHS -> it's a member of typeof(LHS)
  1115. auto [valid, lhsType] = VerifyLHSExprOfMAExprIsValid(ctx);
  1116. return valid ? ComposeMemberNameWithScopeAndGetType(lhsType, ctx->Member)
  1117. : QualifiedName{"<fail>"};
  1118. }
  1119. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::FunctionCallExpressionContext* ctx) const
  1120. {
  1121. // Function call grammar is "Expr arglist" so we need to extract the typeof Expr.
  1122. // which must be a function. (a concrete well resolved function, or an overload set under some conditions)
  1123. // then access its return type and we can return that.
  1124. // it can get complicated in case of overloads.
  1125. auto function{TypeofExpr(ctx->Expr)};
  1126. IdAndKind* symbol = m_symbols->GetIdAndKindInfo(function);
  1127. symbol = ResolveOverload(symbol, ctx->argumentList());
  1128. if (!symbol || !symbol->second.IsKindOneOf(Kind::Function, Kind::OverloadSet))
  1129. {
  1130. return {"<fail>"};
  1131. }
  1132. return GetTypeName(symbol, ForFunctionGetType::Returned);
  1133. }
  1134. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::ArrayAccessExpressionContext* ctx) const
  1135. { // typeof(myvariable[3]) is typeof(myvariable) minus brackets. (e.g. int[] -> int)
  1136. // But because of a limitation, today the type of array variable is not described as type[], but only type
  1137. // which means it is enough today to just return typeof(myvariable).
  1138. // Again, this is loose since array access is not going to be semantically validated.
  1139. // (if you call it on a function for example, it should fail validation; but that's not the mandate of azslc)
  1140. return TypeofExpr(ctx->Expr);
  1141. }
  1142. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::ParenthesizedExpressionContext* ctx) const
  1143. { // parenthesis don't change the type, it's just a syntax precedence thing. so just forward to the inner expression.
  1144. return TypeofExpr(ctx->Expr);
  1145. }
  1146. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::CastExpressionContext* ctx) const
  1147. { // typeof( (type)expr ) is typeof(type) so just forward to that sub rule.
  1148. // Note that the cast-expression can optionally specify array-ranks, but they are ignored today.
  1149. return TypeofExpr(ctx->type());
  1150. }
  1151. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::ConditionalExpressionContext* ctx) const
  1152. { // typeof(a ? b : c) is typeof(b) because b and c are forbidden to differ in type. DXC/clang is going to see to it.
  1153. return TypeofExpr(ctx->TrueExpr);
  1154. }
  1155. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::AssignmentExpressionContext* ctx) const
  1156. { // typeof(a = b) is typeof(a) because an assignment returns a reference to the left-hand-side as rvalue for the enclosing expression.
  1157. return TypeofExpr(ctx->Left);
  1158. }
  1159. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::NumericConstructorExpressionContext* ctx) const
  1160. { // typeof(float2(0,0)) is float2
  1161. return LookupType(ctx->scalarOrVectorOrMatrixType()).GetName();
  1162. }
  1163. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::TypeofExpressionContext* ctx) const
  1164. { // typeof(typeof(..)) is typeof(..) | and typeof(A)::id is type of the symbol composed by `lookup-of-A`/id
  1165. auto leftType = ctx->Expr ? TypeofExpr(ctx->Expr)
  1166. : TypeofExpr(ctx->functionType());
  1167. if (ctx->SubQualification)
  1168. {
  1169. auto [valid, lhsType] = VerifyTypeIsScopeComposable(leftType,
  1170. ctx->Expr ? ctx->Expr->getText()
  1171. : ctx->functionType()->getText(),
  1172. ctx->start->getLine());
  1173. return valid ? ComposeMemberNameWithScopeAndGetType(lhsType, ctx->SubQualification)
  1174. : QualifiedName{"<fail>"};
  1175. }
  1176. return leftType;
  1177. }
  1178. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::LiteralExpressionContext* ctx) const
  1179. {
  1180. return TypeofExpr(ctx->literal());
  1181. }
  1182. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::LiteralContext* ctx) const
  1183. {
  1184. // verifies that our hardcoded strings don't have typo, by checking against the lexer-extracted keywords stored in the Scalar array.
  1185. auto checkExistType = [](string_view scalarName){return std::find(AZ::ShaderCompiler::Predefined::Scalar.begin(), AZ::ShaderCompiler::Predefined::Scalar.end(), scalarName) != AZ::ShaderCompiler::Predefined::Scalar.end();};
  1186. // verifies that last or 1-before-last characters are a particular literal suffix. like in "56ul"
  1187. auto hasSuffix = [](auto node, char s){return tolower(node->getText().back()) == s || tolower(Slice(node->getText(), -3, -2) == s);};
  1188. auto checkAndReturn = [&](string_view typeName)
  1189. {
  1190. assert(checkExistType(typeName));
  1191. return QualifiedName{"?" + string{typeName}};
  1192. };
  1193. if (ctx->True() || ctx->False())
  1194. {
  1195. return checkAndReturn("bool");
  1196. }
  1197. else if (auto* literal = ctx->IntegerLiteral())
  1198. {
  1199. return hasSuffix(literal, 'u') ? checkAndReturn("uint")
  1200. : checkAndReturn("int");
  1201. }
  1202. else if (auto* literal = ctx->FloatLiteral())
  1203. {
  1204. return hasSuffix(literal, 'h') ? checkAndReturn("half")
  1205. : hasSuffix(literal, 'l') ? checkAndReturn("double")
  1206. : checkAndReturn("float");
  1207. }
  1208. return {"<fail>"};
  1209. }
  1210. QualifiedName SemanticOrchestrator::TypeofExpr(azslParser::CommaExpressionContext* ctx) const
  1211. {
  1212. // comma returns whatever is last
  1213. return TypeofExpr(ctx->Right);
  1214. }
  1215. bool SemanticOrchestrator::TryFoldArrayDimensions(AstUnnamedVarDecl* ctx, ArrayDimensions& arrayDimensions)
  1216. {
  1217. for (auto arrayDecl : ctx->ArrayRankSpecifiers)
  1218. {
  1219. if (arrayDecl->Dimension == nullptr)
  1220. {
  1221. arrayDimensions.PushBack(ArrayDimensions::Unbounded);
  1222. }
  1223. else
  1224. {
  1225. ConstNumericVal arrayDimensionVal = FoldEvalStaticConstExprNumericValue(arrayDecl->Dimension);
  1226. int64_t nextDim = ExtractValueAsInt64(arrayDimensionVal, -1);
  1227. if (nextDim < 0)
  1228. {
  1229. verboseCout << arrayDecl->start->getLine() << ": array rank specifier (" << nextDim << ") invalid or non foldable";
  1230. arrayDimensions.PushBack(ArrayDimensions::Unknown);
  1231. }
  1232. else
  1233. {
  1234. int asInt = static_cast<int>(nextDim);
  1235. arrayDimensions.PushBack(asInt);
  1236. }
  1237. }
  1238. }
  1239. return true;
  1240. }
  1241. void SemanticOrchestrator::ValidateClass(azslParser::ClassDefinitionContext* ctx) noexcept(false)
  1242. {
  1243. using namespace std::string_literals;
  1244. auto curScopeName = m_scope->m_currentScopePath;
  1245. verboseCout << ctx->RightBrace()->getSymbol()->getLine() << ": exit class " << curScopeName << ". verifying compliance...\n";
  1246. // Get iterator into the symbol database from current scope name. (current scope should be the currently closing class)
  1247. // Access the KindInfo from iter->second, and "cast" the `anyInfo` variant to ClassInfo:
  1248. auto& classSubInfo = GetCurrentScopeSubInfoAs<ClassInfo>();
  1249. // Semantic validation. Iterate each base UID as registered in the ClassInfo:
  1250. for (auto b : classSubInfo.m_bases)
  1251. {
  1252. // this class original AST node:
  1253. auto declNode = get<AstClassDeclNode*>(classSubInfo.m_declNodeVt);
  1254. // get line location diagnostic message of its declaration keyword in source:
  1255. verboseCout << " base: " << b.m_name << "\n";
  1256. // Fetch the base from name in the database
  1257. auto* infoBase = m_symbols->GetIdAndKindInfo(b.m_name);
  1258. assert(infoBase); // can't be undeclared since it already threw an error in RegisterBases.
  1259. // wannabe is "want-to-be-a-base"
  1260. auto& [baseUid, wannabeInfo] = *infoBase;
  1261. if (wannabeInfo.GetKind() != Kind::Interface)
  1262. {
  1263. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_INTERFACE, declNode->Class()->getSymbol(),
  1264. ConcatString("base ", baseUid.m_name, " is not an interface (it is a "s,
  1265. Kind::ToStr(wannabeInfo.GetKind()).data(), ")"));
  1266. }
  1267. auto& baseInterfaceInfo = wannabeInfo.GetSubRefAs<ClassInfo>();
  1268. for (auto basemember : baseInterfaceInfo.GetOrderedMembers())
  1269. { // Check that any member present in base is present in this class
  1270. if (!classSubInfo.HasMember(basemember.GetNameLeaf()))
  1271. {
  1272. ThrowAzslcOrchestratorException(ORCHESTRATOR_CLASS_REDEFINE, declNode->Class()->getSymbol(),
  1273. ConcatString("class ", m_scope->m_currentScopeUID.m_name, " does not redefine ", basemember.m_name));
  1274. }
  1275. }
  1276. }
  1277. }
  1278. void SemanticOrchestrator::ValidateFunctionAndRegisterFamilySeenat(azslParser::LeadingTypeFunctionSignatureContext* ctx)
  1279. {
  1280. using namespace std::string_literals;
  1281. auto& [thisFuncId, thisFuncKind] = GetCurrentScopeIdAndKind();
  1282. // verify whether it overrides
  1283. auto* parentFunction = GetSymbolHiddenInBase(thisFuncId);
  1284. if (parentFunction)
  1285. {
  1286. // == register this function, to its base symbol's overrides seenat list ! ==
  1287. // let's construct access to that list, from the identifier we got out of GetSymbolHiddenInBase
  1288. auto& [baseFuncId, baseFuncKind] = *parentFunction;
  1289. // let's do a bit of sanity check on that symbol
  1290. Kind baseKind = baseFuncKind.GetKind();
  1291. if (baseKind != Kind::Function)
  1292. { // today, it is impossible to reach that diagnostic, since the grammar doesn't allow it.
  1293. // but we are envisioning Properties as a future possible Kind in interfaces.
  1294. auto baseKindStr = Kind::ToStr(baseKind).data();
  1295. ThrowAzslcOrchestratorException(ORCHESTRATOR_HIDING_SYMBOL_BASE, ctx->Identifier()->getSymbol(),
  1296. ConcatString("function ", thisFuncId.m_name, " is hiding a symbol of a base, that is not of Function kind, but is ", baseKindStr));
  1297. }
  1298. auto& baseFuncSubInfo = baseFuncKind.GetSubRefAs<FunctionInfo>();
  1299. if (std::find(baseFuncSubInfo.m_overrides.begin(), baseFuncSubInfo.m_overrides.end(), thisFuncId) == baseFuncSubInfo.m_overrides.end())
  1300. { // this collection is not a set, and ValidateFunctionAndRegisterFamilySeenat may be called multiple times on the same symbol
  1301. baseFuncSubInfo.m_overrides.emplace_back(thisFuncId);
  1302. }
  1303. // == and register the (one) base in our own data too. two-way 1toN bridging. ==
  1304. auto& thisFuncSubInfo = thisFuncKind.GetSubRefAs<FunctionInfo>();
  1305. thisFuncSubInfo.m_base = baseFuncId;
  1306. }
  1307. // semantic provision of override guarantee:
  1308. if (ctx->Override())
  1309. {
  1310. if (GetCurrentParentScopeIdAndKind().second.GetKind() != Kind::Class)
  1311. { // free function case (or in interface !)
  1312. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_OVERRIDE_SPECIFIER_CLASS, ctx->Identifier()->getSymbol(),
  1313. ConcatString("function ", thisFuncId.m_name, " has override specifier but is not part of a class"));
  1314. }
  1315. else
  1316. { // in-class case
  1317. if (!parentFunction)
  1318. {
  1319. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_OVERRIDE_SPECIFIER_BASE, ctx->Identifier()->getSymbol(),
  1320. ConcatString("method ", thisFuncId.m_name, " has override specifier but is not found in any base"));
  1321. }
  1322. }
  1323. }
  1324. // verify parameters integrity; and reflow the default values into the first declaration site:
  1325. auto& funcInfo = thisFuncKind.GetSubRefAs<FunctionInfo>();
  1326. funcInfo.MergeDefaultParameters();
  1327. // forbid mixup of overloading & default param values (because it wreaks the resolution technique)
  1328. auto overloadSetId = IdentifierUID{QualifiedNameView{RemoveLastParenthesisGroup(thisFuncId.GetName())}};
  1329. auto* overloadSet = m_symbols->GetAsSub<OverloadSetInfo>(overloadSetId);
  1330. if (overloadSet->HasOverloads()) // (at least 2 concrete functions)
  1331. {
  1332. bool thisFuncIsCulprit = funcInfo.HasAnyDefaultParameterValue();
  1333. bool previousFuncIsCulprit = overloadSet->AnyOf([this](auto&& uid){return this->HasAnyDefaultParameterValue(uid);});
  1334. if (thisFuncIsCulprit || previousFuncIsCulprit)
  1335. {
  1336. ThrowAzslcOrchestratorException(ORCHESTRATOR_NO_DEFAULT_PARAM_WITH_OVERLOADS, ctx->Identifier()->getSymbol(),
  1337. ConcatString("can't use default arguments in conjunction with function overloading. (function ", thisFuncId.m_name,
  1338. thisFuncIsCulprit ? " has defaults arguments, but overloads exist)"
  1339. : " overloads a function that has default arguments)"));
  1340. }
  1341. }
  1342. }
  1343. void SemanticOrchestrator::ValidateSrg(azslParser::SrgDefinitionContext* ctx) noexcept(false)
  1344. {
  1345. auto& srgInfo = GetCurrentScopeSubInfoAs<SRGInfo>();
  1346. if (ctx->Semantic)
  1347. {
  1348. string semanticName = ctx->Semantic->getText();
  1349. if (srgInfo.m_semantic)
  1350. {
  1351. // We only care the specified semantic is the same as the currently defined semantic for the srg.
  1352. if (srgInfo.m_semantic->GetNameLeaf() != semanticName)
  1353. {
  1354. const LineDirectiveInfo* originalSrglineInfo = m_preprocessorLineDirectiveFinder->GetNearestPreprocessorLineDirective(srgInfo.m_declNode->Semantic->getLine());
  1355. string errorMsg = FormatString("'partial' extension of ShaderResourceGroup [%s] with semantic [%s] shall not bind a different semantic than [%s] found in line %u of %s",
  1356. ctx->Name->getText().c_str(), semanticName.c_str(), srgInfo.m_semantic->GetNameLeaf().c_str(),
  1357. originalSrglineInfo->m_forcedLineNumber, originalSrglineInfo->m_containingFilename.c_str());
  1358. ThrowAzslcOrchestratorException(ORCHESTRATOR_SRG_EXTENSION_HAS_DIFFERENT_SEMANTIC, ctx->Semantic, errorMsg);
  1359. }
  1360. // All is good.
  1361. return;
  1362. }
  1363. // Make sure the SRG is referencing a registered srgSemantic (and of the correct kind)
  1364. auto uqName = UnqualifiedNameView{ semanticName };
  1365. auto semanticSymbol = LookupSymbol(uqName);
  1366. if (!semanticSymbol)
  1367. {
  1368. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_SEMANTIC_DECLARATION, ctx->ShaderResourceGroup()->getSymbol(),
  1369. ConcatString("Declaration for semantic ", semanticName, " used in SRG ", ctx->Name->getText(), " was not found"));
  1370. }
  1371. auto& [semanticSymId, semanticSymKind] = *semanticSymbol;
  1372. Kind kind = semanticSymKind.GetKind();
  1373. if (kind != Kind::ShaderResourceGroupSemantic)
  1374. {
  1375. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_SEMANTIC_DECLARATION_TYPE, ctx->ShaderResourceGroup()->getSymbol(),
  1376. ConcatString("Declaration for ", semanticName, " used in SRG ", ctx->Name->getText(),
  1377. " is a ", Kind::ToStr(kind).data(),
  1378. " but expected a ", Kind::ToStr(Kind::ShaderResourceGroupSemantic).data()));
  1379. }
  1380. const IdentifierUID& srgId = GetCurrentScopeIdAndKind().first;
  1381. auto* srgSemanticInfo = semanticSymKind.GetSubRefAs<ClassInfo>().Get<SRGSemanticInfo>();
  1382. auto userSrgIterator = m_frequencyToSrg.find(*srgSemanticInfo->m_frequencyId);
  1383. if (userSrgIterator == m_frequencyToSrg.end())
  1384. {
  1385. m_frequencyToSrg[*srgSemanticInfo->m_frequencyId] = srgId;
  1386. }
  1387. else if (userSrgIterator->second != srgId)
  1388. {
  1389. ThrowAzslcOrchestratorException(ORCHESTRATOR_SRG_REUSES_A_FREQUENCY, ctx->ShaderResourceGroup()->getSymbol(),
  1390. ConcatString("SRG ", ctx->Name->getText(), " reuses frequencyId "
  1391. , userSrgIterator->first, " already used by ",
  1392. userSrgIterator->second));
  1393. }
  1394. // Good, the SRGSemantic is valid, remember a reference to its ID on the SRG:
  1395. srgInfo.m_semantic = semanticSymId;
  1396. if (srgSemanticInfo->m_variantFallback)
  1397. {
  1398. int variantFallbackValue = static_cast<int>(*(srgSemanticInfo->m_variantFallback));
  1399. // We pay the price in 16-byte (128-bit) chunks
  1400. int keyLength = ((variantFallbackValue + kShaderVariantKeyRegisterSize - 1) / kShaderVariantKeyRegisterSize) * kShaderVariantKeyRegisterSize;
  1401. if (keyLength > variantFallbackValue)
  1402. {
  1403. PrintWarning(Warn::W1, ctx->ShaderResourceGroup()->getSymbol(),
  1404. "ShaderVariantFallback requires ", variantFallbackValue,
  1405. " bits, but will be bumped up to ", keyLength, " bits for padding.");
  1406. }
  1407. // Find a name that doesn't collide with previous declarations
  1408. string svkName = kShaderVariantKeyFallbackVarName;
  1409. auto existingSymbol = LookupSymbol(UnqualifiedNameView{ svkName });
  1410. while (existingSymbol)
  1411. {
  1412. //There is a name collision, add a suffix to the name and try again.
  1413. svkName = + "z";
  1414. existingSymbol = LookupSymbol(UnqualifiedNameView{ svkName });
  1415. }
  1416. size_t line = 0;
  1417. auto& [uid, var] = AddIdentifier(UnqualifiedNameView{ svkName }, Kind::Variable, line);
  1418. auto& varInfo = var.GetSubAfterInitAs<Kind::Variable>();
  1419. varInfo.m_srgMember = true;
  1420. ArrayDimensions arrayDims;
  1421. arrayDims.PushBack(keyLength / kShaderVariantKeyRegisterSize);
  1422. varInfo.m_typeInfoExt = ExtendedTypeInfo{ CreateTypeRefInfo(UnqualifiedNameView{"uint4"}, OnNotFoundOrWrongKind::Diagnose),
  1423. {}, arrayDims, {}, Packing::MatrixMajor::Default };
  1424. srgInfo.m_implicitStruct.PushMember(uid, Kind::Variable);
  1425. srgInfo.m_shaderVariantFallback = uid;
  1426. }
  1427. }
  1428. for (const IdentifierUID& viewId : srgInfo.m_srViews)
  1429. {
  1430. auto& [_, viewKindInfo] = *m_symbols->GetIdAndKindInfo(viewId.m_name);
  1431. auto& memberInfo = viewKindInfo.GetSubRefAs<VarInfo>();
  1432. // in case of core type: structured buffer
  1433. if (memberInfo.GetTypeClass() == TypeClass::StructuredBuffer)
  1434. {
  1435. // check that generic type is not a view or anything nonsensical
  1436. TypeClass genericClass = memberInfo.GetGenericParameterTypeClass();
  1437. bool genericTypeLooksGood = IsFundamental(genericClass) || IsUserDefined(genericClass);
  1438. if (!genericTypeLooksGood)
  1439. {
  1440. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_EXTERNAL_BOUND_RESOURCE_VIEW, memberInfo.m_declNode->start,
  1441. "externally bound resources can't be type-parameterized on view-types");
  1442. }
  1443. }
  1444. }
  1445. for (const IdentifierUID& cbId : srgInfo.m_CBs)
  1446. {
  1447. auto& [_, kindInfo] = *m_symbols->GetIdAndKindInfo(cbId.m_name);
  1448. auto& memberInfo = kindInfo.GetSubRefAs<VarInfo>();
  1449. assert(memberInfo.IsConstantBuffer());
  1450. const auto& genericName = memberInfo.GetGenericParameterTypeId().m_name;
  1451. auto genericClass = memberInfo.GetGenericParameterTypeClass();
  1452. if (!IsUserDefined(genericClass))
  1453. {
  1454. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_GENERIC_TYPE_CONSTANTBUFFER, memberInfo.m_declNode->start,
  1455. ConcatString("ConstantBuffer<T>'s generic type ", genericName,
  1456. " must be user defined, but seen as ", TypeClass::ToStr(genericClass).data()));
  1457. }
  1458. // further checks by actually fetching the symbol
  1459. IdAndKind* idkind = m_symbols->GetIdAndKindInfo(genericName);
  1460. if (!idkind)
  1461. {
  1462. ThrowAzslcOrchestratorException(ORCHESTRATOR_UNDECLARED_GENERIC_TYPE_CONSTANTBUFFER, memberInfo.m_declNode->start,
  1463. ConcatString("ConstantBuffer<T>'s generic type ", genericName,
  1464. " is not declared!"));
  1465. }
  1466. auto& [id, kind] = *idkind;
  1467. if (kind.GetKind() != Kind::Struct)
  1468. {
  1469. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_GENERIC_TYPE_CONSTANTBUFFER_STRUCT, memberInfo.m_declNode->start,
  1470. ConcatString("ConstantBuffer<T>'s generic type ", genericName,
  1471. " must be a struct, but seen as ", Kind::ToStr(kind.GetKind()).data()));
  1472. }
  1473. }
  1474. }
  1475. optional<int64_t> SemanticOrchestrator::TryFoldSRGSemantic(azslParser::SrgSemanticContext* ctx, size_t semanticTokenType, bool required)
  1476. {
  1477. // const ref used, to extend the returned object's temporary life
  1478. const string& intrinsicVarNameFromLexer = m_lexer->getVocabulary().getLiteralName(semanticTokenType);
  1479. string_view intrinsicVarName = Trim(intrinsicVarNameFromLexer, "\'");
  1480. auto semanticSymbol = LookupSymbol(UnqualifiedNameView{ intrinsicVarName });
  1481. if (!semanticSymbol)
  1482. {
  1483. if (!required)
  1484. {
  1485. return none;
  1486. }
  1487. ThrowAzslcOrchestratorException(ORCHESTRATOR_LITERAL_REQUIRED_SRG_SEMANTIC, ctx->start,
  1488. ConcatString(intrinsicVarName, " is required in SRG semantic"));
  1489. }
  1490. auto&[sId, sKind] = *semanticSymbol;
  1491. auto& srgSubInfo = GetCurrentScopeSubInfoAs<ClassInfo>();
  1492. if (!srgSubInfo.HasMember(sId))
  1493. {
  1494. assert(false); // impossible since already verified above. if we fail here, it's a broken program invariant. (incomplete registration)
  1495. }
  1496. auto& varInfo = sKind.GetSubRefAs<VarInfo>();
  1497. int64_t retValue = 0;
  1498. if (!TryGetConstExprValueAsInt64(varInfo.m_constVal, retValue))
  1499. {
  1500. throw AzslcOrchestratorException(ORCHESTRATOR_INVALID_INTEGER_CONSTANT,
  1501. ConcatString("Semantic pass error: couldn't get a meaningful integer constant for ", intrinsicVarName));
  1502. }
  1503. return retValue;
  1504. }
  1505. void SemanticOrchestrator::ValidateSrgSemantic(azslParser::SrgSemanticContext* ctx)
  1506. {
  1507. auto semanticInfo = GetCurrentScopeSubInfoAs<ClassInfo>().Get<SRGSemanticInfo>();
  1508. (*semanticInfo).m_frequencyId = TryFoldSRGSemantic(ctx, azslParser::FrequencyId, true);
  1509. if (*((*semanticInfo).m_frequencyId) > SRGSemanticInfo_MaxAllowedFrequency)
  1510. {
  1511. ThrowAzslcOrchestratorException(ORCHESTRATOR_INVALID_RANGE_FREQUENCY_ID, ctx->Identifier()->getSymbol(),
  1512. ConcatString("ShaderResourceGroupSemantic must define a FrequencyId with value between 0 and ", SRGSemanticInfo_MaxAllowedFrequency));
  1513. }
  1514. (*semanticInfo).m_variantFallback = TryFoldSRGSemantic(ctx, azslParser::ShaderVariantFallback);
  1515. }
  1516. ConstNumericVal SemanticOrchestrator::FoldEvalStaticConstExprNumericValue(tree::TerminalNode* numericLiteralToken, bool hintAsInt) const noexcept(false)
  1517. {
  1518. string text = numericLiteralToken->getText();
  1519. if (hintAsInt)
  1520. {
  1521. if (EndsWith(text, "u") || EndsWith(text, "U"))
  1522. {
  1523. return static_cast<uint32_t> (std::stoul(text, nullptr, 0/*auto base to support 0#,0x# prefixes*/));
  1524. }
  1525. return int32_t{std::stoi(text, nullptr, 0)}; // stoi(...) resolves floats as integers, use hintAsInt = false if you need a float
  1526. }
  1527. else
  1528. {
  1529. return float{ std::stof(text, nullptr) };
  1530. }
  1531. }
  1532. ConstNumericVal SemanticOrchestrator::FoldEvalStaticConstExprNumericValue(AstIdExpr* idExp) const
  1533. {
  1534. auto uqName = ExtractNameFromIdExpression(idExp);
  1535. auto maybeSymbol = LookupSymbol(uqName);
  1536. if (!maybeSymbol)
  1537. {
  1538. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD_DEFINITION, idExp->start,
  1539. ConcatString("in expected constant expression: identifier ", uqName, " not found"));
  1540. }
  1541. auto& [id, symbol] = *maybeSymbol;
  1542. auto what = symbol.GetKind();
  1543. if (what != Kind::Variable)
  1544. {
  1545. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD_DEFINITION, idExp->start,
  1546. ConcatString("in expected constant expression: identifier ", uqName, " did not refer to a variable, but a ", Kind::ToStr(what).data()));
  1547. }
  1548. auto const& var = symbol.GetSubRefAs<VarInfo>();
  1549. if (holds_alternative<monostate>(var.m_constVal))
  1550. {
  1551. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD_DEFINITION, idExp->start,
  1552. ConcatString("in expected constant expression: variable ", id.m_name, " couldn't be folded to a constant (tip: use --semantic --verbose to diagnose why)"));
  1553. }
  1554. return var.m_constVal;
  1555. }
  1556. namespace
  1557. {
  1558. DiagnosticStream FoldFailedCommonMessage(Token* tok, optional<string_view> identifier = none)
  1559. {
  1560. verboseCout << tok->getLine();
  1561. verboseCout << ": constant folding failed for " << (identifier ? *identifier : tok->getText());
  1562. return verboseCout;
  1563. };
  1564. }
  1565. ConstNumericVal SemanticOrchestrator::FoldEvalStaticConstExprNumericValue(VarInfo& varInfo) const
  1566. {
  1567. auto* declNode = varInfo.m_declNode;
  1568. // first thing: constraint storage-class and type modifiers:
  1569. bool isStaticConst = varInfo.CheckHasAllStorageFlags({StorageFlag::Static, StorageFlag::Const});
  1570. if (!isStaticConst)
  1571. {
  1572. FoldFailedCommonMessage(varInfo.m_declNode->start, string_view{varInfo.m_identifier}) << ": static & const storage flags not set\n";
  1573. return monostate{};
  1574. }
  1575. // second: check initializer syntax nodes
  1576. bool hasInitializer = HasStandardInitializer(declNode);
  1577. bool isStandardExpr = hasInitializer && declNode->variableInitializer()->standardVariableInitializer()->Expr;
  1578. if (isStandardExpr)
  1579. {
  1580. // we support only the expression sub-variant (not arrayElementInitializers and not samplerStateProperty).
  1581. AstExpr* expr = declNode->variableInitializer()->standardVariableInitializer()->Expr;
  1582. return FoldEvalStaticConstExprNumericValue(expr);
  1583. }
  1584. else
  1585. {
  1586. if (!hasInitializer && isStaticConst)
  1587. {
  1588. return int32_t{0}; // non-assigned statics are zero-initialized
  1589. }
  1590. else
  1591. {
  1592. FoldFailedCommonMessage(varInfo.m_declNode->start, string_view{varInfo.m_identifier}) << ": no standard variable initializer expression\n";
  1593. }
  1594. }
  1595. return monostate{};
  1596. }
  1597. ConstNumericVal SemanticOrchestrator::FoldEvalStaticConstExprNumericValue(AstExpr* expr) const
  1598. {
  1599. if (auto* litExpr = As<azslParser::LiteralExpressionContext*>(expr))
  1600. {
  1601. // we are on a literal so we need to restrict down to integers only
  1602. if (auto* intLit = litExpr->literal()->IntegerLiteral())
  1603. { // easy case. we have the literal right there on a plate.
  1604. return FoldEvalStaticConstExprNumericValue(intLit);
  1605. }
  1606. else if (auto* floatLit = litExpr->literal()->FloatLiteral())
  1607. { // easy case. we have the literal right there on a plate.
  1608. return FoldEvalStaticConstExprNumericValue(floatLit, false);
  1609. }
  1610. else
  1611. {
  1612. FoldFailedCommonMessage(expr->start) << ": initializer is not an integer literal\n";
  1613. }
  1614. }
  1615. else if (auto* idExpr = As<azslParser::IdentifierExpressionContext*>(expr))
  1616. {
  1617. // in case of initializers that refers to id, if they are variable they will be already parsed and folded.
  1618. auto uqName = ExtractNameFromIdExpression(idExpr->idExpression());
  1619. auto maybeSymbol = LookupSymbol(uqName);
  1620. if (!maybeSymbol)
  1621. {
  1622. FoldFailedCommonMessage(expr->start) << ": initializer referred to an undeclared symbol " << uqName << "\n";
  1623. return monostate{};
  1624. }
  1625. auto& [id, symbol] = *maybeSymbol;
  1626. auto what = symbol.GetKind();
  1627. if (what != Kind::Variable)
  1628. {
  1629. FoldFailedCommonMessage(expr->start) << ": initializer identifier " + uqName + " did not refer to a variable, but a " + Kind::ToStr(what).data();
  1630. return monostate{};
  1631. }
  1632. auto const& var = symbol.GetSubRefAs<VarInfo>();
  1633. return var.m_constVal;
  1634. }
  1635. else
  1636. {
  1637. FoldFailedCommonMessage(expr->start) << ": variable initializer is not a supported expression\n";
  1638. }
  1639. return monostate{};
  1640. }
  1641. QualifiedName SemanticOrchestrator::MakeFullyQualified(UnqualifiedNameView unqualifiedName) const
  1642. {
  1643. return ::AZ::ShaderCompiler::MakeFullyQualified(m_scope->m_currentScopePath, unqualifiedName);
  1644. }
  1645. TypeClass SemanticOrchestrator::GetTypeClass(IdentifierUID typeId) const
  1646. {
  1647. TypeClass toReturn = TypeClass::IsNotType;
  1648. auto* idKind = m_symbols->GetIdAndKindInfo(typeId.GetName());
  1649. if (idKind) // found
  1650. {
  1651. auto& [_, kind] = *idKind;
  1652. switch (kind.GetKind())
  1653. {
  1654. case Kind::Struct: toReturn = TypeClass::Struct;
  1655. break;
  1656. case Kind::Class: toReturn = TypeClass::Class;
  1657. break;
  1658. case Kind::Enum: toReturn = TypeClass::Enum;
  1659. break;
  1660. case Kind::Interface: toReturn = TypeClass::Interface;
  1661. break;
  1662. case Kind::TypeAlias: toReturn = TypeClass::Alias;
  1663. break;
  1664. default:
  1665. if (auto* asType = kind.GetSubAs<TypeRefInfo>())
  1666. {
  1667. toReturn = asType->m_typeClass;
  1668. }
  1669. break;
  1670. }
  1671. }
  1672. return toReturn;
  1673. }
  1674. IdentifierUID SemanticOrchestrator::LookupType(UnqualifiedNameView typeName, OnNotFoundOrWrongKind policy, optional<size_t> sourceline /*=none*/) const
  1675. {
  1676. auto getErrorIUID = [policy, typeName](){return policy == OnNotFoundOrWrongKind::Empty ? IdentifierUID{} : IdentifierUID{QualifiedName{typeName}};};
  1677. IdAndKind* type = LookupSymbol(UnqualifiedNameView{typeName});
  1678. if (!type)
  1679. {
  1680. if (policy == OnNotFoundOrWrongKind::Diagnose)
  1681. {
  1682. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD_DEFINITION,
  1683. sourceline, none, ConcatString(" type ", string{ typeName }, " requested but not found."));
  1684. }
  1685. else
  1686. {
  1687. return getErrorIUID();
  1688. }
  1689. }
  1690. // found..
  1691. const auto& [uid, kind] = *type;
  1692. // ..is it of correct Kind ?
  1693. bool isType = IsKindOneOfTypeRelated(kind.GetKind());
  1694. if (!isType)
  1695. {
  1696. if (policy == OnNotFoundOrWrongKind::Diagnose)
  1697. {
  1698. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD_DEFINITION,
  1699. sourceline, none, ConcatString(" type ", typeName.data(),
  1700. " requested but found as ", Kind::ToStr(kind.GetKind()).data()));
  1701. }
  1702. else
  1703. {
  1704. return getErrorIUID();
  1705. }
  1706. }
  1707. return {type->first};
  1708. }
  1709. bool SemanticOrchestrator::TryFoldGenericArrayDimensions(ExtractedComposedType& extType, vector<tree::TerminalNode*>& genericDims) const
  1710. {
  1711. for (auto dim : genericDims)
  1712. {
  1713. auto cVal = FoldEvalStaticConstExprNumericValue(dim);
  1714. int64_t nextDim = ExtractValueAsInt64(cVal, -1);
  1715. if (nextDim < 0)
  1716. {
  1717. verboseCout << "SemanticOrchestrator::TryFoldGenericArrayDimensions could not fold the next dimension (" << nextDim << ")!";
  1718. return false;
  1719. // If we might want to allow such cases use this instead:
  1720. // extType.m_genericDimensions.PushBack(ArrayDimensions::unknown);
  1721. }
  1722. else
  1723. {
  1724. int asInt = static_cast<int>(nextDim);
  1725. extType.m_genericDimensions.PushBack(asInt);
  1726. }
  1727. }
  1728. return true;
  1729. }
  1730. ExtendedTypeInfo SemanticOrchestrator::CreateExtendedTypeInfo(AstType* ctx, ArrayDimensions dims, Packing::MatrixMajor mtxMajor) const
  1731. {
  1732. vector<tree::TerminalNode*> genericDims;
  1733. auto extType = ExtractComposedTypeNamesFromAstContext(ctx, &genericDims);
  1734. if (!TryFoldGenericArrayDimensions(extType, genericDims))
  1735. {
  1736. ThrowAzslcOrchestratorException(ORCHESTRATOR_DEPORTED_METHOD_DEFINITION, ctx->start,
  1737. ConcatString("SemanticOrchestrator::CreateExtendedTypeInfo failed for type (", ctx->getText(), ")"));
  1738. }
  1739. return CreateExtendedTypeInfo(extType, dims, mtxMajor);
  1740. }
  1741. ExtendedTypeInfo SemanticOrchestrator::CreateExtendedTypeInfo(AstFuncType* ctx, ArrayDimensions dims, Packing::MatrixMajor mtxMajor) const
  1742. {
  1743. return ctx->Void() ?
  1744. ExtendedTypeInfo{ CreateTypeRefInfo(UnqualifiedNameView{AZ::ShaderCompiler::Predefined::Void[0]}), {}, {}, {}, mtxMajor } :
  1745. CreateExtendedTypeInfo(ctx->type(), dims, mtxMajor);
  1746. }
  1747. ExtendedTypeInfo SemanticOrchestrator::CreateExtendedTypeInfo(const ExtractedComposedType& extractedComposed, ArrayDimensions dims, Packing::MatrixMajor mtxMajor) const
  1748. {
  1749. TypeRefInfo core = CreateTypeRefInfo(extractedComposed.m_core);
  1750. TypeRefInfo generic = CreateTypeRefInfo(extractedComposed.m_genericParam);
  1751. if (core.m_typeClass == TypeClass::Alias)
  1752. {
  1753. // if we're referring to a type alias, follow the trail and collapse the canonical type to its real target.
  1754. // it's unnecessary to loop on this, because the previously registered typealiases are necessarily collapsed.
  1755. // and the first registration is necessarily of an existing type (non alias). by recurrence there can only be a distance of 1 to resolve.
  1756. const TypeAliasInfo* targetAlias = m_symbols->GetAsSub<TypeAliasInfo>(core.m_typeId);
  1757. return targetAlias->m_canonicalType;
  1758. }
  1759. return ExtendedTypeInfo{core, generic, dims, extractedComposed.m_genericDimensions, mtxMajor};
  1760. }
  1761. IdAndKind* SemanticOrchestrator::GetSymbolHiddenInBase(IdentifierUID hidingCandidate)
  1762. {
  1763. IdAndKind* found = nullptr;
  1764. auto& [containingScopeId, containingScopeKind] = GetCurrentParentScopeIdAndKind();
  1765. if (containingScopeKind.GetKind() == Kind::Class) // only class can have bases in AZSL
  1766. {
  1767. // get currently parsed class info:
  1768. auto& curClassInfo = GetCurrentParentScopeSubInfoAs<ClassInfo>();
  1769. // look for a match in any base
  1770. for (const IdentifierUID& base : curClassInfo.m_bases)
  1771. {
  1772. auto maybeBaseClass = m_symbols->GetIdAndKindInfo(base.m_name);
  1773. if (maybeBaseClass
  1774. && maybeBaseClass->second.GetKind() == Kind::Interface) // bases must be interfaces but we don't assume it's enforced prior to calls to this function
  1775. {
  1776. const auto& baseClassInfo = maybeBaseClass->second.GetSubRefAs<ClassInfo>();
  1777. bool baseHasSameNameMember = baseClassInfo.HasMember(hidingCandidate.GetNameLeaf());
  1778. if (baseHasSameNameMember)
  1779. {
  1780. if (found)
  1781. {
  1782. throw AzslcOrchestratorException(ORCHESTRATOR_MULTIPLE_HIDDEN_SYMBOLS,
  1783. ConcatString("Found multiple symbols hidden by ", hidingCandidate.m_name,
  1784. " in bases of ", containingScopeId.m_name,
  1785. ". First was ", found->first.m_name,
  1786. ", now also found in ", base.m_name, "."));
  1787. }
  1788. // reconstruct the UID found, and return that.
  1789. string reconstructedPath = JoinPath(base.m_name, hidingCandidate.GetNameLeaf());
  1790. found = m_symbols->GetIdAndKindInfo(QualifiedName{reconstructedPath});
  1791. }
  1792. }
  1793. }
  1794. }
  1795. return found;
  1796. }
  1797. bool SemanticOrchestrator::IsScopeStructClassInterface() const
  1798. {
  1799. const KindInfo& scopeKind = m_symbols->GetIdAndKindInfo(m_scope->GetNameOfCurScope())->second;
  1800. return scopeKind.IsKindOneOf(Kind::Struct, Kind::Class, Kind::Interface);
  1801. }
  1802. void SemanticOrchestrator::MakeAndEnterAnonymousScope(string_view decorationPrefix, Token* scopeFirstToken)
  1803. {
  1804. UnqualifiedName unnamedBlockCode{ConcatString("$", decorationPrefix, m_anonymousCounter)};
  1805. AddIdentifier(unnamedBlockCode, Kind::Namespace, scopeFirstToken->getLine());
  1806. m_scope->EnterScope(unnamedBlockCode, scopeFirstToken->getTokenIndex());
  1807. ++m_anonymousCounter;
  1808. }
  1809. }