Fix variable scoping of do-while
[platform/upstream/glslang.git] / glslang / MachineIndependent / iomapper.cpp
1 //
2 // Copyright (C) 2016-2017 LunarG, Inc.
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 //    Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 //
13 //    Redistributions in binary form must reproduce the above
14 //    copyright notice, this list of conditions and the following
15 //    disclaimer in the documentation and/or other materials provided
16 //    with the distribution.
17 //
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 //    contributors may be used to endorse or promote products derived
20 //    from this software without specific prior written permission.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
34 //
35
36 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
37
38 #include "../Include/Common.h"
39 #include "../Include/InfoSink.h"
40 #include "../Include/Types.h"
41
42 #include "gl_types.h"
43 #include "iomapper.h"
44 #include "SymbolTable.h"
45
46 //
47 // Map IO bindings.
48 //
49 // High-level algorithm for one stage:
50 //
51 // 1. Traverse all code (live+dead) to find the explicitly provided bindings.
52 //
53 // 2. Traverse (just) the live code to determine which non-provided bindings
54 //    require auto-numbering.  We do not auto-number dead ones.
55 //
56 // 3. Traverse all the code to apply the bindings:
57 //    a. explicitly given bindings are offset according to their type
58 //    b. implicit live bindings are auto-numbered into the holes, using
59 //       any open binding slot.
60 //    c. implicit dead bindings are left un-bound.
61 //
62
63 namespace glslang {
64
65 class TVarGatherTraverser : public TLiveTraverser {
66 public:
67     TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList)
68       : TLiveTraverser(i, traverseDeadCode, true, true, false)
69       , inputList(inList)
70       , outputList(outList)
71       , uniformList(uniformList)
72     {
73     }
74
75     virtual void visitSymbol(TIntermSymbol* base)
76     {
77         TVarLiveMap* target = nullptr;
78         if (base->getQualifier().storage == EvqVaryingIn)
79             target = &inputList;
80         else if (base->getQualifier().storage == EvqVaryingOut)
81             target = &outputList;
82         else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().isPushConstant())
83             target = &uniformList;
84         // If a global is being visited, then we should also traverse it incase it's evaluation
85         // ends up visiting inputs we want to tag as live
86         else if (base->getQualifier().storage == EvqGlobal)
87             addGlobalReference(base->getAccessName());
88
89         if (target) {
90             TVarEntryInfo ent = {base->getId(), base, ! traverseAll};
91             ent.stage = intermediate.getStage();
92             TVarLiveMap::iterator at = target->find(
93                 ent.symbol->getAccessName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById());
94             if (at != target->end() && at->second.id == ent.id)
95                 at->second.live = at->second.live || ! traverseAll; // update live state
96             else
97                 (*target)[ent.symbol->getAccessName()] = ent;
98         }
99     }
100
101 private:
102     TVarLiveMap&    inputList;
103     TVarLiveMap&    outputList;
104     TVarLiveMap&    uniformList;
105 };
106
107 class TVarSetTraverser : public TLiveTraverser
108 {
109 public:
110     TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& inList, const TVarLiveMap& outList, const TVarLiveMap& uniformList)
111       : TLiveTraverser(i, true, true, true, false)
112       , inputList(inList)
113       , outputList(outList)
114       , uniformList(uniformList)
115     {
116     }
117
118     virtual void visitSymbol(TIntermSymbol* base) {
119         const TVarLiveMap* source;
120         if (base->getQualifier().storage == EvqVaryingIn)
121             source = &inputList;
122         else if (base->getQualifier().storage == EvqVaryingOut)
123             source = &outputList;
124         else if (base->getQualifier().isUniformOrBuffer())
125             source = &uniformList;
126         else
127             return;
128
129         TVarEntryInfo ent = { base->getId() };
130         // Fix a defect, when block has no instance name, we need to find its block name
131         TVarLiveMap::const_iterator at = source->find(base->getAccessName());
132         if (at == source->end())
133             return;
134
135         if (at->second.id != ent.id)
136             return;
137
138         if (at->second.newBinding != -1)
139             base->getWritableType().getQualifier().layoutBinding = at->second.newBinding;
140         if (at->second.newSet != -1)
141             base->getWritableType().getQualifier().layoutSet = at->second.newSet;
142         if (at->second.newLocation != -1)
143             base->getWritableType().getQualifier().layoutLocation = at->second.newLocation;
144         if (at->second.newComponent != -1)
145             base->getWritableType().getQualifier().layoutComponent = at->second.newComponent;
146         if (at->second.newIndex != -1)
147             base->getWritableType().getQualifier().layoutIndex = at->second.newIndex;
148     }
149
150   private:
151     const TVarLiveMap&    inputList;
152     const TVarLiveMap&    outputList;
153     const TVarLiveMap&    uniformList;
154 };
155
156 struct TNotifyUniformAdaptor
157 {
158     EShLanguage stage;
159     TIoMapResolver& resolver;
160     inline TNotifyUniformAdaptor(EShLanguage s, TIoMapResolver& r)
161       : stage(s)
162       , resolver(r)
163     {
164     }
165
166     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
167     {
168         resolver.notifyBinding(stage, entKey.second);
169     }
170
171 private:
172     TNotifyUniformAdaptor& operator=(TNotifyUniformAdaptor&) = delete;
173 };
174
175 struct TNotifyInOutAdaptor
176 {
177     EShLanguage stage;
178     TIoMapResolver& resolver;
179     inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r) 
180       : stage(s)
181       , resolver(r)
182     {
183     }
184
185     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
186     {
187         resolver.notifyInOut(entKey.second.stage, entKey.second);
188     }
189
190 private:
191     TNotifyInOutAdaptor& operator=(TNotifyInOutAdaptor&) = delete;
192 };
193
194 struct TResolverUniformAdaptor {
195     TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TVarLiveMap* uniform[EShLangCount], TInfoSink& i, bool& e)
196       : stage(s)
197       , resolver(r)
198       , infoSink(i)
199       , error(e)
200     {
201         memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
202     }
203
204     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
205         TVarEntryInfo& ent = entKey.second;
206         ent.newLocation = -1;
207         ent.newComponent = -1;
208         ent.newBinding = -1;
209         ent.newSet = -1;
210         ent.newIndex = -1;
211         const bool isValid = resolver.validateBinding(stage, ent);
212         if (isValid) {
213             resolver.resolveSet(ent.stage, ent);
214             resolver.resolveBinding(ent.stage, ent);
215             resolver.resolveUniformLocation(ent.stage, ent);
216
217             if (ent.newBinding != -1) {
218                 if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
219                     TString err = "mapped binding out of range: " + entKey.first;
220
221                     infoSink.info.message(EPrefixInternalError, err.c_str());
222                     error = true;
223                 }
224
225                 if (ent.symbol->getQualifier().hasBinding()) {
226                     for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
227                         if (idx == ent.stage || uniformVarMap[idx] == nullptr)
228                             continue;
229                         auto entKey2 = uniformVarMap[idx]->find(entKey.first);
230                         if (entKey2 != uniformVarMap[idx]->end()) {
231                             entKey2->second.newBinding = ent.newBinding;
232                         }
233                     }
234                 }
235             }
236             if (ent.newSet != -1) {
237                 if (ent.newSet >= int(TQualifier::layoutSetEnd)) {
238                     TString err = "mapped set out of range: " + entKey.first;
239
240                     infoSink.info.message(EPrefixInternalError, err.c_str());
241                     error = true;
242                 }
243                 if (ent.symbol->getQualifier().hasSet()) {
244                     for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
245                         if ((idx == stage) || (uniformVarMap[idx] == nullptr))
246                             continue;
247                         auto entKey2 = uniformVarMap[idx]->find(entKey.first);
248                         if (entKey2 != uniformVarMap[idx]->end()) {
249                             entKey2->second.newSet = ent.newSet;
250                         }
251                     }
252                 }
253             }
254         } else {
255             TString errorMsg = "Invalid binding: " + entKey.first;
256             infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
257             error = true;
258         }
259     }
260
261     inline void setStage(EShLanguage s) { stage = s; }
262
263     EShLanguage     stage;
264     TIoMapResolver& resolver;
265     TInfoSink&      infoSink;
266     bool&           error;
267     TVarLiveMap*    uniformVarMap[EShLangCount];
268 private:
269     TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete;
270 };
271
272 struct TResolverInOutAdaptor {
273     TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e)
274       : stage(s)
275       , resolver(r)
276       , infoSink(i)
277       , error(e)
278     {
279     }
280
281     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
282     {
283         TVarEntryInfo& ent = entKey.second;
284         ent.newLocation = -1;
285         ent.newComponent = -1;
286         ent.newBinding = -1;
287         ent.newSet = -1;
288         ent.newIndex = -1;
289         const bool isValid = resolver.validateInOut(ent.stage, ent);
290         if (isValid) {
291             resolver.resolveInOutLocation(stage, ent);
292             resolver.resolveInOutComponent(stage, ent);
293             resolver.resolveInOutIndex(stage, ent);
294         } else {
295             TString errorMsg;
296             if (ent.symbol->getType().getQualifier().semanticName != nullptr) {
297                 errorMsg = "Invalid shader In/Out variable semantic: ";
298                 errorMsg += ent.symbol->getType().getQualifier().semanticName;
299             } else {
300                 errorMsg = "Invalid shader In/Out variable: ";
301                 errorMsg += ent.symbol->getName();
302             }
303             infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
304             error = true;
305         }
306     }
307
308     inline void setStage(EShLanguage s) { stage = s; }
309
310     EShLanguage     stage;
311     TIoMapResolver& resolver;
312     TInfoSink&      infoSink;
313     bool&           error;
314
315 private:
316     TResolverInOutAdaptor& operator=(TResolverInOutAdaptor&) = delete;
317 };
318
319 // The class is used for reserving explicit uniform locations and ubo/ssbo/opaque bindings
320 // xxTODO: maybe this logic should be moved into the resolver's "validateInOut" and "validateUniform"
321
322 struct TSymbolValidater
323 {
324     TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount],
325                      TVarLiveMap* uniform[EShLangCount], bool& hadError, EProfile profile, int version)
326         : resolver(r)
327         , infoSink(i)
328         , hadError(hadError)
329         , profile(profile)
330         , version(version)
331     {
332         memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*)));
333         memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*)));
334         memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
335
336         std::map<TString, TString> anonymousMemberMap;
337         std::vector<TRange> usedUniformLocation;
338         std::vector<TString> usedUniformName;
339         usedUniformLocation.clear();
340         usedUniformName.clear();
341         for (int i = 0; i < EShLangCount; i++) {
342             if (uniformVarMap[i]) {
343                 for (auto uniformVar : *uniformVarMap[i])
344                 {
345                     TIntermSymbol* pSymbol = uniformVar.second.symbol;
346                     TQualifier qualifier = uniformVar.second.symbol->getQualifier();
347                     TString symbolName = pSymbol->getAccessName();
348
349                     // All the uniform needs multi-stage location check (block/default)
350                     int uniformLocation = qualifier.layoutLocation;
351
352                     if (uniformLocation != TQualifier::layoutLocationEnd) {
353                         // Total size of current uniform, could be block, struct or other types.
354                         int size = TIntermediate::computeTypeUniformLocationSize(pSymbol->getType());
355
356                         TRange locationRange(uniformLocation, uniformLocation + size - 1);
357
358                         // Combine location and component ranges
359                         int overlapLocation = -1;
360                         bool diffLocation = false;
361
362                         // Check for collisions, except for vertex inputs on desktop targeting OpenGL
363                         overlapLocation = checkLocationOverlap(locationRange, usedUniformLocation, symbolName, usedUniformName, diffLocation);
364
365                         // Overlap locations of uniforms, regardless of components (multi stages)
366                         if (overlapLocation == -1) {
367                             usedUniformLocation.push_back(locationRange);
368                             usedUniformName.push_back(symbolName);
369                         }
370                         else if (overlapLocation >= 0) {
371                             if (diffLocation == true) {
372                                 TString err = ("Uniform location should be equal for same uniforms: " +std::to_string(overlapLocation)).c_str();
373                                 infoSink.info.message(EPrefixInternalError, err.c_str());
374                                 hadError = true;
375                                 break;
376                             }
377                             else {
378                                 TString err = ("Uniform location overlaps across stages: " + std::to_string(overlapLocation)).c_str();
379                                 infoSink.info.message(EPrefixInternalError, err.c_str());
380                                 hadError = true;
381                                 break;
382                             }
383                         }
384                     }
385
386                     if ((uniformVar.second.symbol->getBasicType() == EbtBlock) &&
387                         IsAnonymous(uniformVar.second.symbol->getName()))
388                     {
389                         auto blockType = uniformVar.second.symbol->getType().getStruct();
390                         for (size_t memberIdx = 0; memberIdx < blockType->size(); ++memberIdx) {
391                             auto memberName = (*blockType)[memberIdx].type->getFieldName();
392                             if (anonymousMemberMap.find(memberName) != anonymousMemberMap.end())
393                             {
394                                 if (anonymousMemberMap[memberName] != uniformVar.second.symbol->getType().getTypeName())
395                                 {
396                                     TString err = "Invalid block member name: " + memberName;
397                                     infoSink.info.message(EPrefixInternalError, err.c_str());
398                                     hadError = true;
399                                     break;
400                                 }
401                             }
402                             else
403                             {
404                                 anonymousMemberMap[memberName] = uniformVar.second.symbol->getType().getTypeName();
405                             }
406                         }
407                     }
408                     if (hadError)
409                         break;
410                 }
411             }
412         }
413     }
414
415     // In case we need to new an intermediate, which costs too much
416     int checkLocationOverlap(const TRange& locationRange, std::vector<TRange>& usedUniformLocation, const TString symbolName, std::vector<TString>& usedUniformName, bool& diffLocation)
417     {
418         for (size_t r = 0; r < usedUniformLocation.size(); ++r) {
419             if (usedUniformName[r] == symbolName) {
420                 diffLocation = true;
421                 return (usedUniformLocation[r].start == locationRange.start &&
422                         usedUniformLocation[r].last == locationRange.last)
423                        ? -2 : std::max(locationRange.start, usedUniformLocation[r].start);
424             }
425             if (locationRange.overlap(usedUniformLocation[r])) {
426                 // there is a collision; pick one
427                 return std::max(locationRange.start, usedUniformLocation[r].start);
428             }
429         }
430
431         return -1; // no collision
432     }
433
434     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
435         TVarEntryInfo& ent1 = entKey.second;
436         TIntermSymbol* base = ent1.symbol;
437         const TType& type = ent1.symbol->getType();
438         const TString& name = entKey.first;
439         TString mangleName1, mangleName2;
440         EShLanguage stage = ent1.stage;
441         EShLanguage preStage, currentStage, nextStage;
442
443         preStage = EShLangCount;
444         for (int i = stage - 1; i >= 0; i--) {
445             if (inVarMaps[i] != nullptr) {
446                 preStage = static_cast<EShLanguage>(i);
447                 break;
448             }
449         }
450         currentStage = stage;
451         nextStage = EShLangCount;
452         for (int i = stage + 1; i < EShLangCount; i++) {
453             if (inVarMaps[i] != nullptr) {
454                 nextStage = static_cast<EShLanguage>(i);
455                 break;
456             }
457         }
458
459         if (type.getQualifier().isArrayedIo(stage)) {
460             TType subType(type, 0);
461             subType.appendMangledName(mangleName1);
462         } else {
463             type.appendMangledName(mangleName1);
464         }
465
466
467         // basic checking that symbols match
468         // more extensive checking in the link stage
469         if (base->getQualifier().storage == EvqVaryingIn) {
470             // validate stage in;
471             if (preStage == EShLangCount)
472                 return;
473             if (TSymbolTable::isBuiltInSymbol(base->getId()))
474                 return;
475             if (outVarMaps[preStage] != nullptr) {
476                 auto ent2 = outVarMaps[preStage]->find(name);
477                 uint32_t location = base->getType().getQualifier().layoutLocation;
478                 if (ent2 == outVarMaps[preStage]->end() &&
479                     location != glslang::TQualifier::layoutLocationEnd) {
480                     for (auto var = outVarMaps[preStage]->begin(); var != ent2; var++) {
481                         if (var->second.symbol->getType().getQualifier().layoutLocation == location) {
482                             ent2 = var;
483                             break;
484                         }
485                     }
486                 }
487                 if (ent2 != outVarMaps[preStage]->end()) {
488                     auto& type1 = base->getType();
489                     auto& type2 = ent2->second.symbol->getType();
490                     hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
491                     if (ent2->second.symbol->getType().getQualifier().isArrayedIo(preStage)) {
492                         TType subType(ent2->second.symbol->getType(), 0);
493                         subType.appendMangledName(mangleName2);
494                     } else {
495                         ent2->second.symbol->getType().appendMangledName(mangleName2);
496                     }
497
498                     if (mangleName1 == mangleName2) {
499                         // For ES 3.0 only, other versions have no such restrictions
500                         // According to ES 3.0 spec: The type and presence of the interpolation qualifiers and
501                         // storage qualifiers  of variables with the same name declared in all linked shaders must
502                         // match, otherwise the link command will fail.
503                         if (profile == EEsProfile && version == 300) {
504                             // Don't need to check smooth qualifier, as it uses the default interpolation mode
505                             if (ent1.stage == EShLangFragment && type1.isBuiltIn() == false) {
506                                 if (type1.getQualifier().flat != type2.getQualifier().flat ||
507                                     type1.getQualifier().nopersp != type2.getQualifier().nopersp) {
508                                     TString err = "Interpolation qualifier mismatch : " + entKey.first;
509                                     infoSink.info.message(EPrefixInternalError, err.c_str());
510                                     hadError = true;
511                                 }
512                             }
513                         }
514                         return;
515                     }
516                     else {
517                         TString err = "Invalid In/Out variable type : " + entKey.first;
518                         infoSink.info.message(EPrefixInternalError, err.c_str());
519                         hadError = true;
520                     }
521                 }
522                 else if (!base->getType().isBuiltIn()) {
523                     // According to spec: A link error is generated if any statically referenced input variable
524                     // or block does not have a matching output
525                     if (profile == EEsProfile && ent1.live) {
526                         hadError = true;
527                         TString errorStr = name + ": not been declare as a output variable in pre shader stage.";
528                         infoSink.info.message(EPrefixError, errorStr.c_str());
529                     }
530                 }
531                 return;
532             }
533         } else if (base->getQualifier().storage == EvqVaryingOut) {
534             // validate stage out;
535             if (nextStage == EShLangCount)
536                 return;
537             if (TSymbolTable::isBuiltInSymbol(base->getId()))
538                 return;
539             if (inVarMaps[nextStage] != nullptr) {
540                 auto ent2 = inVarMaps[nextStage]->find(name);
541                 if (ent2 != inVarMaps[nextStage]->end()) {
542                     if (ent2->second.symbol->getType().getQualifier().isArrayedIo(nextStage)) {
543                         TType subType(ent2->second.symbol->getType(), 0);
544                         subType.appendMangledName(mangleName2);
545                     } else {
546                         ent2->second.symbol->getType().appendMangledName(mangleName2);
547                     }
548                     if (mangleName1 == mangleName2)
549                         return;
550                     else {
551                         TString err = "Invalid In/Out variable type : " + entKey.first;
552                         infoSink.info.message(EPrefixInternalError, err.c_str());
553                         hadError = true;
554                     }
555                 }
556                 return;
557             }
558         } else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().isPushConstant()) {
559             // validate uniform type;
560             for (int i = 0; i < EShLangCount; i++) {
561                 if (i != currentStage && outVarMaps[i] != nullptr) {
562                     auto ent2 = uniformVarMap[i]->find(name);
563                     if (ent2 != uniformVarMap[i]->end()) {
564                         ent2->second.symbol->getType().appendMangledName(mangleName2);
565                         if (mangleName1 != mangleName2) {
566                             ent2->second.symbol->getType().sameElementType(type);
567                             TString err = "Invalid Uniform variable type : " + entKey.first;
568                             infoSink.info.message(EPrefixInternalError, err.c_str());
569                             hadError = true;
570                         }
571                         mangleName2.clear();
572
573                         // validate instance name of blocks
574                         if (hadError == false &&
575                             base->getType().getBasicType() == EbtBlock &&
576                             IsAnonymous(base->getName()) != IsAnonymous(ent2->second.symbol->getName())) {
577                             TString err = "Matched uniform block names must also either all be lacking "
578                                           "an instance name or all having an instance name: " + entKey.first;
579                             infoSink.info.message(EPrefixInternalError, err.c_str());
580                             hadError = true;
581                         }
582
583                         // validate uniform block member qualifier and member names
584                         auto& type1 = base->getType();
585                         auto& type2 = ent2->second.symbol->getType();
586                         if (hadError == false && base->getType().getBasicType() == EbtBlock) {
587                             hadError = hadError || typeCheck(&type1, &type2, name.c_str(), true);
588                         }
589                         else {
590                             hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
591                         }
592                     }
593                     else if (base->getBasicType() == EbtBlock)
594                     {
595                         if (IsAnonymous(base->getName()))
596                         {
597                             // The name of anonymous block member can't same with default uniform variable.
598                             auto blockType1 = base->getType().getStruct();
599                             for (size_t memberIdx = 0; memberIdx < blockType1->size(); ++memberIdx) {
600                                 auto memberName = (*blockType1)[memberIdx].type->getFieldName();
601                                 if (uniformVarMap[i]->find(memberName) != uniformVarMap[i]->end())
602                                 {
603                                     TString err = "Invalid Uniform variable name : " + memberName;
604                                     infoSink.info.message(EPrefixInternalError, err.c_str());
605                                     hadError = true;
606                                     break;
607                                 }
608                             }
609                         }
610                     }
611                 }
612             }
613         }
614     }
615
616     TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount];
617
618     // Use for mark current shader stage for resolver
619     TIoMapResolver& resolver;
620     TInfoSink& infoSink;
621     bool& hadError;
622     EProfile profile;
623     int version;
624
625 private:
626     TSymbolValidater& operator=(TSymbolValidater&) = delete;
627
628     bool qualifierCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
629     {
630         bool hasError = false;
631         const TQualifier& qualifier1 = type1->getQualifier();
632         const TQualifier& qualifier2 = type2->getQualifier();
633
634         if (((isBlock == false) &&
635             (type1->getQualifier().storage == EvqUniform && type2->getQualifier().storage == EvqUniform)) ||
636             (type1->getQualifier().storage == EvqGlobal && type2->getQualifier().storage == EvqGlobal)) {
637             if (qualifier1.precision != qualifier2.precision) {
638                 hasError = true;
639                 std::string errorStr = name + ": have precision conflict cross stage.";
640                 infoSink.info.message(EPrefixError, errorStr.c_str());
641             }
642             if (qualifier1.hasFormat() && qualifier2.hasFormat()) {
643                 if (qualifier1.layoutFormat != qualifier2.layoutFormat) {
644                     hasError = true;
645                     std::string errorStr = name + ": have layout format conflict cross stage.";
646                     infoSink.info.message(EPrefixError, errorStr.c_str());
647                 }
648
649             }
650         }
651
652         if (isBlock == true) {
653             if (qualifier1.layoutPacking != qualifier2.layoutPacking) {
654                 hasError = true;
655                 std::string errorStr = name + ": have layoutPacking conflict cross stage.";
656                 infoSink.info.message(EPrefixError, errorStr.c_str());
657             }
658             if (qualifier1.layoutMatrix != qualifier2.layoutMatrix) {
659                 hasError = true;
660                 std::string errorStr = name + ": have layoutMatrix conflict cross stage.";
661                 infoSink.info.message(EPrefixError, errorStr.c_str());
662             }
663             if (qualifier1.layoutOffset != qualifier2.layoutOffset) {
664                 hasError = true;
665                 std::string errorStr = name + ": have layoutOffset conflict cross stage.";
666                 infoSink.info.message(EPrefixError, errorStr.c_str());
667             }
668             if (qualifier1.layoutAlign != qualifier2.layoutAlign) {
669                 hasError = true;
670                 std::string errorStr = name + ": have layoutAlign conflict cross stage.";
671                 infoSink.info.message(EPrefixError, errorStr.c_str());
672             }
673         }
674
675         return hasError;
676     }
677
678     bool typeCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
679     {
680         bool hasError = false;
681         if (!(type1->isStruct() && type2->isStruct())) {
682             hasError = hasError || qualifierCheck(type1, type2, name, isBlock);
683         }
684         else {
685             if (type1->getBasicType() == EbtBlock && type2->getBasicType() == EbtBlock)
686                 isBlock = true;
687             const TTypeList* typeList1 = type1->getStruct();
688             const TTypeList* typeList2 = type2->getStruct();
689
690             std::string newName = name;
691             size_t memberCount = typeList1->size();
692             size_t index2 = 0;
693             for (size_t index = 0; index < memberCount; index++, index2++) {
694                 // Skip inactive member
695                 if (typeList1->at(index).type->getBasicType() == EbtVoid)
696                     continue;
697                 while (index2 < typeList2->size() && typeList2->at(index2).type->getBasicType() == EbtVoid) {
698                     ++index2;
699                 }
700
701                 // TypeList1 has more members in list
702                 if (index2 == typeList2->size()) {
703                     std::string errorStr = name + ": struct mismatch.";
704                     infoSink.info.message(EPrefixError, errorStr.c_str());
705                     hasError = true;
706                     break;
707                 }
708
709                 if (typeList1->at(index).type->getFieldName() != typeList2->at(index2).type->getFieldName()) {
710                     std::string errorStr = name + ": member name mismatch.";
711                     infoSink.info.message(EPrefixError, errorStr.c_str());
712                     hasError = true;
713                 }
714                 else {
715                     newName = typeList1->at(index).type->getFieldName().c_str();
716                 }
717                 hasError = hasError || typeCheck(typeList1->at(index).type, typeList2->at(index2).type, newName, isBlock);
718             }
719
720             while (index2 < typeList2->size())
721             {
722                 // TypeList2 has more members
723                 if (typeList2->at(index2).type->getBasicType() != EbtVoid) {
724                     std::string errorStr = name + ": struct mismatch.";
725                     infoSink.info.message(EPrefixError, errorStr.c_str());
726                     hasError = true;
727                     break;
728                 }
729                 ++index2;
730             }
731         }
732         return hasError;
733     }
734 };
735
736 struct TSlotCollector {
737     TSlotCollector(TIoMapResolver& r, TInfoSink& i) : resolver(r), infoSink(i) { }
738
739     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
740         resolver.reserverStorageSlot(entKey.second, infoSink);
741         resolver.reserverResourceSlot(entKey.second, infoSink);
742     }
743     TIoMapResolver& resolver;
744     TInfoSink& infoSink;
745
746 private:
747     TSlotCollector& operator=(TSlotCollector&) = delete;
748 };
749
750 TDefaultIoResolverBase::TDefaultIoResolverBase(const TIntermediate& intermediate)
751     : intermediate(intermediate)
752     , nextUniformLocation(intermediate.getUniformLocationBase())
753     , nextInputLocation(0)
754     , nextOutputLocation(0)
755 {
756     memset(stageMask, false, sizeof(bool) * (EShLangCount + 1));
757     memset(stageIntermediates, 0, sizeof(TIntermediate*) * (EShLangCount));
758     stageIntermediates[intermediate.getStage()] = &intermediate;
759 }
760
761 int TDefaultIoResolverBase::getBaseBinding(EShLanguage stage, TResourceType res, unsigned int set) const {
762     return stageIntermediates[stage] ? selectBaseBinding(stageIntermediates[stage]->getShiftBinding(res), stageIntermediates[stage]->getShiftBindingForSet(res, set))
763                                      : selectBaseBinding(intermediate.getShiftBinding(res), intermediate.getShiftBindingForSet(res, set));
764 }
765
766 const std::vector<std::string>& TDefaultIoResolverBase::getResourceSetBinding(EShLanguage stage) const {
767     return stageIntermediates[stage] ? stageIntermediates[stage]->getResourceSetBinding()
768                                      : intermediate.getResourceSetBinding();
769 }
770
771 bool TDefaultIoResolverBase::doAutoBindingMapping() const { return intermediate.getAutoMapBindings(); }
772
773 bool TDefaultIoResolverBase::doAutoLocationMapping() const { return intermediate.getAutoMapLocations(); }
774
775 TDefaultIoResolverBase::TSlotSet::iterator TDefaultIoResolverBase::findSlot(int set, int slot) {
776     return std::lower_bound(slots[set].begin(), slots[set].end(), slot);
777 }
778
779 bool TDefaultIoResolverBase::checkEmpty(int set, int slot) {
780     TSlotSet::iterator at = findSlot(set, slot);
781     return ! (at != slots[set].end() && *at == slot);
782 }
783
784 int TDefaultIoResolverBase::reserveSlot(int set, int slot, int size) {
785     TSlotSet::iterator at = findSlot(set, slot);
786     // tolerate aliasing, by not double-recording aliases
787     // (policy about appropriateness of the alias is higher up)
788     for (int i = 0; i < size; i++) {
789         if (at == slots[set].end() || *at != slot + i)
790             at = slots[set].insert(at, slot + i);
791         ++at;
792     }
793     return slot;
794 }
795
796 int TDefaultIoResolverBase::getFreeSlot(int set, int base, int size) {
797     TSlotSet::iterator at = findSlot(set, base);
798     if (at == slots[set].end())
799         return reserveSlot(set, base, size);
800     // look for a big enough gap
801     for (; at != slots[set].end(); ++at) {
802         if (*at - base >= size)
803             break;
804         base = *at + 1;
805     }
806     return reserveSlot(set, base, size);
807 }
808
809 int TDefaultIoResolverBase::resolveSet(EShLanguage stage, TVarEntryInfo& ent) {
810     const TType& type = ent.symbol->getType();
811     if (type.getQualifier().hasSet()) {
812         return ent.newSet = type.getQualifier().layoutSet;
813     }
814     // If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN)
815     if (getResourceSetBinding(stage).size() == 1) {
816         return ent.newSet = atoi(getResourceSetBinding(stage)[0].c_str());
817     }
818     return ent.newSet = 0;
819 }
820
821 int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
822     const TType& type = ent.symbol->getType();
823     const char* name =  ent.symbol->getAccessName().c_str();
824     // kick out of not doing this
825     if (! doAutoLocationMapping()) {
826         return ent.newLocation = -1;
827     }
828     // no locations added if already present, a built-in variable, a block, or an opaque
829     if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock ||
830         type.isAtomic() || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) {
831         return ent.newLocation = -1;
832     }
833     // no locations on blocks of built-in variables
834     if (type.isStruct()) {
835         if (type.getStruct()->size() < 1) {
836             return ent.newLocation = -1;
837         }
838         if ((*type.getStruct())[0].type->isBuiltIn()) {
839             return ent.newLocation = -1;
840         }
841     }
842     int location = intermediate.getUniformLocationOverride(name);
843     if (location != -1) {
844         return ent.newLocation = location;
845     }
846     location = nextUniformLocation;
847     nextUniformLocation += TIntermediate::computeTypeUniformLocationSize(type);
848     return ent.newLocation = location;
849 }
850
851 int TDefaultIoResolverBase::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
852     const TType& type = ent.symbol->getType();
853     // kick out of not doing this
854     if (! doAutoLocationMapping()) {
855         return ent.newLocation = -1;
856     }
857
858     // no locations added if already present, or a built-in variable
859     if (type.getQualifier().hasLocation() || type.isBuiltIn()) {
860         return ent.newLocation = -1;
861     }
862
863     // no locations on blocks of built-in variables
864     if (type.isStruct()) {
865         if (type.getStruct()->size() < 1) {
866             return ent.newLocation = -1;
867         }
868         if ((*type.getStruct())[0].type->isBuiltIn()) {
869             return ent.newLocation = -1;
870         }
871     }
872     // point to the right input or output location counter
873     int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation;
874     // Placeholder. This does not do proper cross-stage lining up, nor
875     // work with mixed location/no-location declarations.
876     int location = nextLocation;
877     int typeLocationSize;
878     // Don’t take into account the outer-most array if the stage’s
879     // interface is automatically an array.
880     typeLocationSize = computeTypeLocationSize(type, stage);
881     nextLocation += typeLocationSize;
882     return ent.newLocation = location;
883 }
884
885 int TDefaultIoResolverBase::resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) {
886     return ent.newComponent = -1;
887 }
888
889 int TDefaultIoResolverBase::resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) { return ent.newIndex = -1; }
890
891 uint32_t TDefaultIoResolverBase::computeTypeLocationSize(const TType& type, EShLanguage stage) {
892     int typeLocationSize;
893     // Don’t take into account the outer-most array if the stage’s
894     // interface is automatically an array.
895     if (type.getQualifier().isArrayedIo(stage)) {
896         TType elementType(type, 0);
897         typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage);
898     } else {
899         typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage);
900     }
901     return typeLocationSize;
902 }
903
904 //TDefaultGlslIoResolver
905 TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type) {
906     if (isImageType(type)) {
907         return EResImage;
908     }
909     if (isTextureType(type)) {
910         return EResTexture;
911     }
912     if (isSsboType(type)) {
913         return EResSsbo;
914     }
915     if (isSamplerType(type)) {
916         return EResSampler;
917     }
918     if (isUboType(type)) {
919         return EResUbo;
920     }
921     return EResCount;
922 }
923
924 TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate)
925     : TDefaultIoResolverBase(intermediate)
926     , preStage(EShLangCount)
927     , currentStage(EShLangCount)
928 { }
929
930 int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
931     const TType& type = ent.symbol->getType();
932     const TString& name = ent.symbol->getAccessName();
933     if (currentStage != stage) {
934         preStage = currentStage;
935         currentStage = stage;
936     }
937     // kick out if not doing this
938     if (! doAutoLocationMapping()) {
939         return ent.newLocation = -1;
940     }
941     // expand the location to each element if the symbol is a struct or array
942     if (type.getQualifier().hasLocation()) {
943         return ent.newLocation = type.getQualifier().layoutLocation;
944     }
945     // no locations added if already present, or a built-in variable
946     if (type.isBuiltIn()) {
947         return ent.newLocation = -1;
948     }
949     // no locations on blocks of built-in variables
950     if (type.isStruct()) {
951         if (type.getStruct()->size() < 1) {
952             return ent.newLocation = -1;
953         }
954         if ((*type.getStruct())[0].type->isBuiltIn()) {
955             return ent.newLocation = -1;
956         }
957     }
958     int typeLocationSize = computeTypeLocationSize(type, stage);
959     int location = type.getQualifier().layoutLocation;
960     bool hasLocation = false;
961     EShLanguage keyStage(EShLangCount);
962     TStorageQualifier storage;
963     storage = EvqInOut;
964     if (type.getQualifier().isPipeInput()) {
965         // If this symbol is a input, search pre stage's out
966         keyStage = preStage;
967     }
968     if (type.getQualifier().isPipeOutput()) {
969         // If this symbol is a output, search next stage's in
970         keyStage = currentStage;
971     }
972     // The in/out in current stage is not declared with location, but it is possible declared
973     // with explicit location in other stages, find the storageSlotMap firstly to check whether
974     // the in/out has location
975     int resourceKey = buildStorageKey(keyStage, storage);
976     if (! storageSlotMap[resourceKey].empty()) {
977         TVarSlotMap::iterator iter = storageSlotMap[resourceKey].find(name);
978         if (iter != storageSlotMap[resourceKey].end()) {
979             // If interface resource be found, set it has location and this symbol's new location
980             // equal the symbol's explicit location declaration in pre or next stage.
981             //
982             // vs:    out vec4 a;
983             // fs:    layout(..., location = 3,...) in vec4 a;
984             hasLocation = true;
985             location = iter->second;
986             // if we want deal like that:
987             // vs:    layout(location=4) out vec4 a;
988             //        out vec4 b;
989             //
990             // fs:    in vec4 a;
991             //        layout(location = 4) in vec4 b;
992             // we need retraverse the map.
993         }
994         if (! hasLocation) {
995             // If interface resource note found, It's mean the location in two stage are both implicit declarat.
996             // So we should find a new slot for this interface.
997             //
998             // vs: out vec4 a;
999             // fs: in vec4 a;
1000             location = getFreeSlot(resourceKey, 0, typeLocationSize);
1001             storageSlotMap[resourceKey][name] = location;
1002         }
1003     } else {
1004         // the first interface declarated in a program.
1005         TVarSlotMap varSlotMap;
1006         location = getFreeSlot(resourceKey, 0, typeLocationSize);
1007         varSlotMap[name] = location;
1008         storageSlotMap[resourceKey] = varSlotMap;
1009     }
1010     //Update location
1011     return ent.newLocation = location;
1012 }
1013
1014 int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
1015     const TType& type = ent.symbol->getType();
1016     const TString& name = ent.symbol->getAccessName();
1017     // kick out of not doing this
1018     if (! doAutoLocationMapping()) {
1019         return ent.newLocation = -1;
1020     }
1021     // expand the location to each element if the symbol is a struct or array
1022     if (type.getQualifier().hasLocation() && (type.isStruct() || type.isArray())) {
1023         return ent.newLocation = type.getQualifier().layoutLocation;
1024     } else {
1025         // no locations added if already present, a built-in variable, a block, or an opaque
1026         if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock ||
1027             type.isAtomic() || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) {
1028             return ent.newLocation = -1;
1029         }
1030         // no locations on blocks of built-in variables
1031         if (type.isStruct()) {
1032             if (type.getStruct()->size() < 1) {
1033                 return ent.newLocation = -1;
1034             }
1035             if ((*type.getStruct())[0].type->isBuiltIn()) {
1036                 return ent.newLocation = -1;
1037             }
1038         }
1039     }
1040     int location = intermediate.getUniformLocationOverride(name.c_str());
1041     if (location != -1) {
1042         return ent.newLocation = location;
1043     }
1044
1045     int size = TIntermediate::computeTypeUniformLocationSize(type);
1046
1047     // The uniform in current stage is not declared with location, but it is possible declared
1048     // with explicit location in other stages, find the storageSlotMap firstly to check whether
1049     // the uniform has location
1050     bool hasLocation = false;
1051     int resourceKey = buildStorageKey(EShLangCount, EvqUniform);
1052     TVarSlotMap& slotMap = storageSlotMap[resourceKey];
1053     // Check dose shader program has uniform resource
1054     if (! slotMap.empty()) {
1055         // If uniform resource not empty, try find a same name uniform
1056         TVarSlotMap::iterator iter = slotMap.find(name);
1057         if (iter != slotMap.end()) {
1058             // If uniform resource be found, set it has location and this symbol's new location
1059             // equal the uniform's explicit location declaration in other stage.
1060             //
1061             // vs:    uniform vec4 a;
1062             // fs:    layout(..., location = 3,...) uniform vec4 a;
1063             hasLocation = true;
1064             location = iter->second;
1065         }
1066         if (! hasLocation) {
1067             // No explicit location declaration in other stage.
1068             // So we should find a new slot for this uniform.
1069             //
1070             // vs:    uniform vec4 a;
1071             // fs:    uniform vec4 a;
1072             location = getFreeSlot(resourceKey, 0, computeTypeLocationSize(type, currentStage));
1073             storageSlotMap[resourceKey][name] = location;
1074         }
1075     } else {
1076         // the first uniform declaration in a program.
1077         TVarSlotMap varSlotMap;
1078         location = getFreeSlot(resourceKey, 0, size);
1079         varSlotMap[name] = location;
1080         storageSlotMap[resourceKey] = varSlotMap;
1081     }
1082     return ent.newLocation = location;
1083 }
1084
1085 int TDefaultGlslIoResolver::resolveBinding(EShLanguage stage, TVarEntryInfo& ent) {
1086     const TType& type = ent.symbol->getType();
1087     const TString& name = ent.symbol->getAccessName();
1088     // On OpenGL arrays of opaque types take a separate binding for each element
1089     int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
1090     TResourceType resource = getResourceType(type);
1091     // don't need to handle uniform symbol, it will be handled in resolveUniformLocation
1092     if (resource == EResUbo && type.getBasicType() != EbtBlock) {
1093         return ent.newBinding = -1;
1094     }
1095     // There is no 'set' qualifier in OpenGL shading language, each resource has its own
1096     // binding name space, so remap the 'set' to resource type which make each resource
1097     // binding is valid from 0 to MAX_XXRESOURCE_BINDINGS
1098     int set = intermediate.getSpv().openGl != 0 ? resource : ent.newSet;
1099     int resourceKey = set;
1100     if (resource < EResCount) {
1101         if (type.getQualifier().hasBinding()) {
1102             int newBinding = reserveSlot(resourceKey, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding, numBindings);
1103             return ent.newBinding = newBinding;
1104
1105         } else {
1106             // The resource in current stage is not declared with binding, but it is possible declared
1107             // with explicit binding in other stages, find the resourceSlotMap firstly to check whether
1108             // the resource has binding, don't need to allocate if it already has a binding
1109             bool hasBinding = false;
1110             ent.newBinding = -1; // leave as -1 if it isn't set below
1111
1112             if (! resourceSlotMap[resourceKey].empty()) {
1113                 TVarSlotMap::iterator iter = resourceSlotMap[resourceKey].find(name);
1114                 if (iter != resourceSlotMap[resourceKey].end()) {
1115                     hasBinding = true;
1116                     ent.newBinding = iter->second;
1117                 }
1118             }
1119             if (!hasBinding && (ent.live && doAutoBindingMapping())) {
1120                 // find free slot, the caller did make sure it passes all vars with binding
1121                 // first and now all are passed that do not have a binding and needs one
1122                 int binding = getFreeSlot(resourceKey, getBaseBinding(stage, resource, set), numBindings);
1123                 resourceSlotMap[resourceKey][name] = binding;
1124                 ent.newBinding = binding;
1125             }
1126             return ent.newBinding;
1127         }
1128     }
1129     return ent.newBinding = -1;
1130 }
1131
1132 void TDefaultGlslIoResolver::beginResolve(EShLanguage stage) {
1133     // reset stage state
1134     if (stage == EShLangCount)
1135         preStage = currentStage = stage;
1136     // update stage state
1137     else if (currentStage != stage) {
1138         preStage = currentStage;
1139         currentStage = stage;
1140     }
1141 }
1142
1143 void TDefaultGlslIoResolver::endResolve(EShLanguage /*stage*/) {
1144     // TODO nothing
1145 }
1146
1147 void TDefaultGlslIoResolver::beginCollect(EShLanguage stage) {
1148     // reset stage state
1149     if (stage == EShLangCount)
1150         preStage = currentStage = stage;
1151     // update stage state
1152     else if (currentStage != stage) {
1153         preStage = currentStage;
1154         currentStage = stage;
1155     }
1156 }
1157
1158 void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) {
1159     // TODO nothing
1160 }
1161
1162 void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
1163     const TType& type = ent.symbol->getType();
1164     const TString& name = ent.symbol->getAccessName();
1165     TStorageQualifier storage = type.getQualifier().storage;
1166     EShLanguage stage(EShLangCount);
1167     switch (storage) {
1168     case EvqUniform:
1169         if (type.getBasicType() != EbtBlock && type.getQualifier().hasLocation()) {
1170             //
1171             // Reserve the slots for the uniforms who has explicit location
1172             int storageKey = buildStorageKey(EShLangCount, EvqUniform);
1173             int location = type.getQualifier().layoutLocation;
1174             TVarSlotMap& varSlotMap = storageSlotMap[storageKey];
1175             TVarSlotMap::iterator iter = varSlotMap.find(name);
1176             if (iter == varSlotMap.end()) {
1177                 int numLocations = TIntermediate::computeTypeUniformLocationSize(type);
1178                 reserveSlot(storageKey, location, numLocations);
1179                 varSlotMap[name] = location;
1180             } else {
1181                 // Allocate location by name for OpenGL driver, so the uniform in different
1182                 // stages should be declared with the same location
1183                 if (iter->second != location) {
1184                     TString errorMsg = "Invalid location: " + name;
1185                     infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
1186                     hasError = true;
1187                 }
1188             }
1189         }
1190         break;
1191     case EvqVaryingIn:
1192     case EvqVaryingOut:
1193         //
1194         // Reserve the slots for the inout who has explicit location
1195         if (type.getQualifier().hasLocation()) {
1196             stage = storage == EvqVaryingIn ? preStage : stage;
1197             stage = storage == EvqVaryingOut ? currentStage : stage;
1198             int storageKey = buildStorageKey(stage, EvqInOut);
1199             int location = type.getQualifier().layoutLocation;
1200             TVarSlotMap& varSlotMap = storageSlotMap[storageKey];
1201             TVarSlotMap::iterator iter = varSlotMap.find(name);
1202             if (iter == varSlotMap.end()) {
1203                 int numLocations = TIntermediate::computeTypeUniformLocationSize(type);
1204                 reserveSlot(storageKey, location, numLocations);
1205                 varSlotMap[name] = location;
1206             } else {
1207                 // Allocate location by name for OpenGL driver, so the uniform in different
1208                 // stages should be declared with the same location
1209                 if (iter->second != location) {
1210                     TString errorMsg = "Invalid location: " + name;
1211                     infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
1212                     hasError = true;
1213                 }
1214             }
1215         }
1216         break;
1217     default:
1218         break;
1219     }
1220 }
1221
1222 void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
1223     const TType& type = ent.symbol->getType();
1224     const TString& name = ent.symbol->getAccessName();
1225     TResourceType resource = getResourceType(type);
1226     int set = intermediate.getSpv().openGl != 0 ? resource : resolveSet(ent.stage, ent);
1227     int resourceKey = set;
1228
1229     if (type.getQualifier().hasBinding()) {
1230         TVarSlotMap& varSlotMap = resourceSlotMap[resourceKey];
1231         TVarSlotMap::iterator iter = varSlotMap.find(name);
1232         int binding = type.getQualifier().layoutBinding + getBaseBinding(ent.stage, resource, set);
1233
1234         if (iter == varSlotMap.end()) {
1235             // Reserve the slots for the ubo, ssbo and opaques who has explicit binding
1236             int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
1237             varSlotMap[name] = binding;
1238             reserveSlot(resourceKey, binding, numBindings);
1239         } else {
1240             // Allocate binding by name for OpenGL driver, so the resource in different
1241             // stages should be declared with the same binding
1242             if (iter->second != binding) {
1243                 TString errorMsg = "Invalid binding: " + name;
1244                 infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
1245                 hasError = true;
1246             }
1247         }
1248     }
1249 }
1250
1251 //TDefaultGlslIoResolver end
1252
1253 /*
1254  * Basic implementation of glslang::TIoMapResolver that replaces the
1255  * previous offset behavior.
1256  * It does the same, uses the offsets for the corresponding uniform
1257  * types. Also respects the EOptionAutoMapBindings flag and binds
1258  * them if needed.
1259  */
1260 /*
1261  * Default resolver
1262  */
1263 struct TDefaultIoResolver : public TDefaultIoResolverBase {
1264     TDefaultIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { }
1265
1266     bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
1267
1268     TResourceType getResourceType(const glslang::TType& type) override {
1269         if (isImageType(type)) {
1270             return EResImage;
1271         }
1272         if (isTextureType(type)) {
1273             return EResTexture;
1274         }
1275         if (isSsboType(type)) {
1276             return EResSsbo;
1277         }
1278         if (isSamplerType(type)) {
1279             return EResSampler;
1280         }
1281         if (isUboType(type)) {
1282             return EResUbo;
1283         }
1284         return EResCount;
1285     }
1286
1287     int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) override {
1288         const TType& type = ent.symbol->getType();
1289         const int set = getLayoutSet(type);
1290         // On OpenGL arrays of opaque types take a seperate binding for each element
1291         int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
1292         TResourceType resource = getResourceType(type);
1293         if (resource < EResCount) {
1294             if (type.getQualifier().hasBinding()) {
1295                 return ent.newBinding = reserveSlot(
1296                            set, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding, numBindings);
1297             } else if (ent.live && doAutoBindingMapping()) {
1298                 // find free slot, the caller did make sure it passes all vars with binding
1299                 // first and now all are passed that do not have a binding and needs one
1300                 return ent.newBinding = getFreeSlot(set, getBaseBinding(stage, resource, set), numBindings);
1301             }
1302         }
1303         return ent.newBinding = -1;
1304     }
1305 };
1306
1307 #ifdef ENABLE_HLSL
1308 /********************************************************************************
1309 The following IO resolver maps types in HLSL register space, as follows:
1310
1311 t - for shader resource views (SRV)
1312    TEXTURE1D
1313    TEXTURE1DARRAY
1314    TEXTURE2D
1315    TEXTURE2DARRAY
1316    TEXTURE3D
1317    TEXTURECUBE
1318    TEXTURECUBEARRAY
1319    TEXTURE2DMS
1320    TEXTURE2DMSARRAY
1321    STRUCTUREDBUFFER
1322    BYTEADDRESSBUFFER
1323    BUFFER
1324    TBUFFER
1325
1326 s - for samplers
1327    SAMPLER
1328    SAMPLER1D
1329    SAMPLER2D
1330    SAMPLER3D
1331    SAMPLERCUBE
1332    SAMPLERSTATE
1333    SAMPLERCOMPARISONSTATE
1334
1335 u - for unordered access views (UAV)
1336    RWBYTEADDRESSBUFFER
1337    RWSTRUCTUREDBUFFER
1338    APPENDSTRUCTUREDBUFFER
1339    CONSUMESTRUCTUREDBUFFER
1340    RWBUFFER
1341    RWTEXTURE1D
1342    RWTEXTURE1DARRAY
1343    RWTEXTURE2D
1344    RWTEXTURE2DARRAY
1345    RWTEXTURE3D
1346
1347 b - for constant buffer views (CBV)
1348    CBUFFER
1349    CONSTANTBUFFER
1350  ********************************************************************************/
1351 struct TDefaultHlslIoResolver : public TDefaultIoResolverBase {
1352     TDefaultHlslIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { }
1353
1354     bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
1355
1356     TResourceType getResourceType(const glslang::TType& type) override {
1357         if (isUavType(type)) {
1358             return EResUav;
1359         }
1360         if (isSrvType(type)) {
1361             return EResTexture;
1362         }
1363         if (isSamplerType(type)) {
1364             return EResSampler;
1365         }
1366         if (isUboType(type)) {
1367             return EResUbo;
1368         }
1369         return EResCount;
1370     }
1371
1372     int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) override {
1373         const TType& type = ent.symbol->getType();
1374         const int set = getLayoutSet(type);
1375         TResourceType resource = getResourceType(type);
1376         if (resource < EResCount) {
1377             if (type.getQualifier().hasBinding()) {
1378                 return ent.newBinding = reserveSlot(set, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding);
1379             } else if (ent.live && doAutoBindingMapping()) {
1380                 // find free slot, the caller did make sure it passes all vars with binding
1381                 // first and now all are passed that do not have a binding and needs one
1382                 return ent.newBinding = getFreeSlot(set, getBaseBinding(stage, resource, set));
1383             }
1384         }
1385         return ent.newBinding = -1;
1386     }
1387 };
1388 #endif
1389
1390 // Map I/O variables to provided offsets, and make bindings for
1391 // unbound but live variables.
1392 //
1393 // Returns false if the input is too malformed to do this.
1394 bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
1395     bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() ||
1396                          intermediate.getAutoMapLocations();
1397     // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce
1398     // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true.
1399     for (int res = 0; (res < EResCount && !somethingToDo); ++res) {
1400         somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) ||
1401                         intermediate.hasShiftBindingForSet(TResourceType(res));
1402     }
1403     if (! somethingToDo && resolver == nullptr)
1404         return true;
1405     if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
1406         return false;
1407     TIntermNode* root = intermediate.getTreeRoot();
1408     if (root == nullptr)
1409         return false;
1410     // if no resolver is provided, use the default resolver with the given shifts and auto map settings
1411     TDefaultIoResolver defaultResolver(intermediate);
1412 #ifdef ENABLE_HLSL
1413     TDefaultHlslIoResolver defaultHlslResolver(intermediate);
1414     if (resolver == nullptr) {
1415         // TODO: use a passed in IO mapper for this
1416         if (intermediate.usingHlslIoMapping())
1417             resolver = &defaultHlslResolver;
1418         else
1419             resolver = &defaultResolver;
1420     }
1421 #else
1422     resolver = &defaultResolver;
1423 #endif
1424     resolver->addStage(stage, intermediate);
1425
1426     TVarLiveMap inVarMap, outVarMap, uniformVarMap;
1427     TVarLiveVector inVector, outVector, uniformVector;
1428     TVarGatherTraverser iter_binding_all(intermediate, true, inVarMap, outVarMap, uniformVarMap);
1429     TVarGatherTraverser iter_binding_live(intermediate, false, inVarMap, outVarMap, uniformVarMap);
1430     root->traverse(&iter_binding_all);
1431     iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str());
1432     while (! iter_binding_live.destinations.empty()) {
1433         TIntermNode* destination = iter_binding_live.destinations.back();
1434         iter_binding_live.destinations.pop_back();
1435         destination->traverse(&iter_binding_live);
1436     }
1437
1438     // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
1439     for (auto& var : inVarMap) { inVector.push_back(var); }
1440     std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1441         return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1442     });
1443     for (auto& var : outVarMap) { outVector.push_back(var); }
1444     std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1445         return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1446     });
1447     for (auto& var : uniformVarMap) { uniformVector.push_back(var); }
1448     std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1449         return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1450     });
1451     bool hadError = false;
1452     TVarLiveMap* dummyUniformVarMap[EShLangCount] = {};
1453     TNotifyInOutAdaptor inOutNotify(stage, *resolver);
1454     TNotifyUniformAdaptor uniformNotify(stage, *resolver);
1455     TResolverUniformAdaptor uniformResolve(stage, *resolver, dummyUniformVarMap, infoSink, hadError);
1456     TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError);
1457     resolver->beginNotifications(stage);
1458     std::for_each(inVector.begin(), inVector.end(), inOutNotify);
1459     std::for_each(outVector.begin(), outVector.end(), inOutNotify);
1460     std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify);
1461     resolver->endNotifications(stage);
1462     resolver->beginResolve(stage);
1463     for (auto& var : inVector) { inOutResolve(var); }
1464     std::for_each(inVector.begin(), inVector.end(), [&inVarMap](TVarLivePair p) {
1465         auto at = inVarMap.find(p.second.symbol->getAccessName());
1466         if (at != inVarMap.end() && p.second.id == at->second.id)
1467             at->second = p.second;
1468     });
1469     for (auto& var : outVector) { inOutResolve(var); }
1470     std::for_each(outVector.begin(), outVector.end(), [&outVarMap](TVarLivePair p) {
1471         auto at = outVarMap.find(p.second.symbol->getAccessName());
1472         if (at != outVarMap.end() && p.second.id == at->second.id)
1473             at->second = p.second;
1474     });
1475     std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
1476     std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) {
1477         auto at = uniformVarMap.find(p.second.symbol->getAccessName());
1478         if (at != uniformVarMap.end() && p.second.id == at->second.id)
1479             at->second = p.second;
1480     });
1481     resolver->endResolve(stage);
1482     if (!hadError) {
1483         TVarSetTraverser iter_iomap(intermediate, inVarMap, outVarMap, uniformVarMap);
1484         root->traverse(&iter_iomap);
1485     }
1486     return !hadError;
1487 }
1488
1489 // Map I/O variables to provided offsets, and make bindings for
1490 // unbound but live variables.
1491 //
1492 // Returns false if the input is too malformed to do this.
1493 bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
1494     bool somethingToDo = !intermediate.getResourceSetBinding().empty() ||
1495         intermediate.getAutoMapBindings() ||
1496         intermediate.getAutoMapLocations();
1497
1498     // Profile and version are use for symbol validate.
1499     profile = intermediate.getProfile();
1500     version = intermediate.getVersion();
1501
1502     // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce
1503     // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true.
1504     for (int res = 0; (res < EResCount && !somethingToDo); ++res) {
1505         somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) ||
1506                         intermediate.hasShiftBindingForSet(TResourceType(res));
1507     }
1508     if (! somethingToDo && resolver == nullptr) {
1509         return true;
1510     }
1511     if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) {
1512         return false;
1513     }
1514     TIntermNode* root = intermediate.getTreeRoot();
1515     if (root == nullptr) {
1516         return false;
1517     }
1518     // if no resolver is provided, use the default resolver with the given shifts and auto map settings
1519     TDefaultGlslIoResolver defaultResolver(intermediate);
1520 #ifdef ENABLE_HLSL
1521     TDefaultHlslIoResolver defaultHlslResolver(intermediate);
1522     if (resolver == nullptr) {
1523         // TODO: use a passed in IO mapper for this
1524         if (intermediate.usingHlslIoMapping())
1525             resolver = &defaultHlslResolver;
1526         else
1527             resolver = &defaultResolver;
1528     }
1529 #else
1530     if (resolver == nullptr) {
1531         resolver = &defaultResolver;
1532     }
1533 #endif
1534     resolver->addStage(stage, intermediate);
1535     inVarMaps[stage] = new TVarLiveMap(); outVarMaps[stage] = new TVarLiveMap(); uniformVarMap[stage] = new TVarLiveMap();
1536     TVarGatherTraverser iter_binding_all(intermediate, true, *inVarMaps[stage], *outVarMaps[stage],
1537                                          *uniformVarMap[stage]);
1538     TVarGatherTraverser iter_binding_live(intermediate, false, *inVarMaps[stage], *outVarMaps[stage],
1539                                           *uniformVarMap[stage]);
1540     root->traverse(&iter_binding_all);
1541     iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str());
1542     while (! iter_binding_live.destinations.empty()) {
1543         TIntermNode* destination = iter_binding_live.destinations.back();
1544         iter_binding_live.destinations.pop_back();
1545         destination->traverse(&iter_binding_live);
1546     }
1547
1548     TNotifyInOutAdaptor inOutNotify(stage, *resolver);
1549     TNotifyUniformAdaptor uniformNotify(stage, *resolver);
1550     // Resolve current stage input symbol location with previous stage output here,
1551     // uniform symbol, ubo, ssbo and opaque symbols are per-program resource,
1552     // will resolve uniform symbol location and ubo/ssbo/opaque binding in doMap()
1553     resolver->beginNotifications(stage);
1554     std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutNotify);
1555     std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutNotify);
1556     std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), uniformNotify);
1557     resolver->endNotifications(stage);
1558     TSlotCollector slotCollector(*resolver, infoSink);
1559     resolver->beginCollect(stage);
1560     std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), slotCollector);
1561     std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), slotCollector);
1562     std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), slotCollector);
1563     resolver->endCollect(stage);
1564     intermediates[stage] = &intermediate;
1565     return !hadError;
1566 }
1567
1568 bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
1569     resolver->endResolve(EShLangCount);
1570     if (!hadError) {
1571         //Resolve uniform location, ubo/ssbo/opaque bindings across stages
1572         TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, uniformVarMap, infoSink, hadError);
1573         TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError);
1574         TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps,
1575                                          outVarMaps, uniformVarMap, hadError, profile, version);
1576
1577         TVarLiveVector inVectors[EShLangCount];
1578         TVarLiveVector outVectors[EShLangCount];
1579         TVarLiveVector uniformVector;
1580
1581         resolver->beginResolve(EShLangCount);
1582         for (int stage = EShLangVertex; stage < EShLangCount; stage++) {
1583             if (inVarMaps[stage] != nullptr) {
1584                 inOutResolve.setStage(EShLanguage(stage));
1585
1586                 // copy vars into a sorted list
1587                 std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(),
1588                         [&inVectors, stage](TVarLivePair p) { inVectors[stage].push_back(p); });
1589                 std::sort(inVectors[stage].begin(), inVectors[stage].end(),
1590                         [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1591                             return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1592                 });
1593
1594                 std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(),
1595                         [&outVectors, stage](TVarLivePair p) { outVectors[stage].push_back(p); });
1596                 std::sort(outVectors[stage].begin(), outVectors[stage].end(),
1597                         [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1598                             return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1599                 });
1600
1601                 for (auto& var : inVectors[stage]) { symbolValidater(var); }
1602                 for (auto& var : inVectors[stage]) { inOutResolve(var); }
1603                 for (auto& var : outVectors[stage]) { symbolValidater(var); }
1604                 for (auto& var : outVectors[stage]) { inOutResolve(var); }
1605
1606                 // copy results back into maps
1607                 std::for_each(inVectors[stage].begin(), inVectors[stage].end(),
1608                     [this, stage](TVarLivePair p) {
1609                         auto at = inVarMaps[stage]->find(p.first);
1610                         if (at != inVarMaps[stage]->end())
1611                             at->second = p.second;
1612                 });
1613
1614                 std::for_each(outVectors[stage].begin(), outVectors[stage].end(),
1615                     [this, stage](TVarLivePair p) {
1616                         auto at = outVarMaps[stage]->find(p.first);
1617                         if (at != outVarMaps[stage]->end())
1618                             at->second = p.second;
1619                 });
1620
1621             }
1622             if (uniformVarMap[stage] != nullptr) {
1623                 uniformResolve.setStage(EShLanguage(stage));
1624                 for (auto& var : *(uniformVarMap[stage])) { uniformVector.push_back(var); }
1625             }
1626         }
1627         std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1628             return TVarEntryInfo::TOrderByPriorityAndLive()(p1.second, p2.second);
1629         });
1630         for (auto& var : uniformVector) { symbolValidater(var); }
1631         for (auto& var : uniformVector) { uniformResolve(var); }
1632         std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1633             return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1634         });
1635         resolver->endResolve(EShLangCount);
1636         if (autoPushConstantBlockName.length()) {
1637             bool upgraded = false;
1638             for (size_t stage = 0; stage < EShLangCount; stage++) {
1639                 if (intermediates[stage] != nullptr) {
1640                     TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap;
1641                     auto at = pUniformVarMap[stage]->find(autoPushConstantBlockName);
1642                     if (at == pUniformVarMap[stage]->end())
1643                         continue;
1644                     TQualifier& qualifier = at->second.symbol->getQualifier();
1645                     if (!qualifier.isUniform())
1646                         continue;
1647                     TType& t = at->second.symbol->getWritableType();
1648                     int size, stride;
1649                     TIntermediate::getBaseAlignment(t, size, stride, autoPushConstantBlockPacking,
1650                                                     qualifier.layoutMatrix == ElmRowMajor);
1651                     if (size <= int(autoPushConstantMaxSize)) {
1652                         qualifier.setBlockStorage(EbsPushConstant);
1653                         qualifier.layoutPacking = autoPushConstantBlockPacking;
1654                         upgraded = true;
1655                     }
1656                 }
1657             }
1658             // If it's been upgraded to push_constant, then remove it from the uniformVector
1659             // so it doesn't get a set/binding assigned to it.
1660             if (upgraded) {
1661                 auto at = std::find_if(uniformVector.begin(), uniformVector.end(),
1662                                        [this](const TVarLivePair& p) { return p.first == autoPushConstantBlockName; });
1663                 if (at != uniformVector.end())
1664                     uniformVector.erase(at);
1665             }
1666         }
1667         for (size_t stage = 0; stage < EShLangCount; stage++) {
1668             if (intermediates[stage] != nullptr) {
1669                 // traverse each stage, set new location to each input/output and unifom symbol, set new binding to
1670                 // ubo, ssbo and opaque symbols
1671                 TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap;
1672                 std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) {
1673                     auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName());
1674                     if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){
1675                         int resolvedBinding = at->second.newBinding;
1676                         at->second = p.second;
1677                         if (resolvedBinding > 0)
1678                             at->second.newBinding = resolvedBinding;
1679                     }
1680                 });
1681                 TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage],
1682                                             *uniformResolve.uniformVarMap[stage]);
1683                 intermediates[stage]->getTreeRoot()->traverse(&iter_iomap);
1684             }
1685         }
1686         return !hadError;
1687     } else {
1688         return false;
1689     }
1690 }
1691
1692 } // end namespace glslang
1693
1694 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE