void SymbolTable::EvalFunctionReferenceClosure() { for (auto & func : Functions) { List<String> funcList; EnumerableHashSet<String> funcSet; for (auto & ref : func.Value->ReferencedFunctions) { funcList.Add(ref); funcSet.Add(ref); } for (int i = 0; i < funcList.Count(); i++) { RefPtr<FunctionSymbol> funcSym; if (Functions.TryGetValue(funcList[i], funcSym)) { for (auto rfunc : funcSym->ReferencedFunctions) { if (funcSet.Add(rfunc)) funcList.Add(rfunc); } } } func.Value->ReferencedFunctions = _Move(funcSet); } }
void ShaderIR::EliminateDeadCode() { // mark entry points auto MarkUsing = [&](String compName, String userWorld) { if (auto defs = DefinitionsByComponent.TryGetValue(compName)) { if (auto def = defs->TryGetValue(userWorld)) (*def)->IsEntryPoint = true; else { for (auto & world : Shader->Pipeline->WorldDependency[userWorld]()) { if (auto def2 = defs->TryGetValue(world)) { (*def2)->IsEntryPoint = true; break; } } } } }; for (auto & impOp : Shader->Pipeline->SyntaxNode->ImportOperators) for (auto & ref : impOp->Usings) MarkUsing(ref.Content, impOp->DestWorld.Content); for (auto & w : Shader->Pipeline->SyntaxNode->Worlds) for (auto & ref : w->Usings) MarkUsing(ref.Content, w->Name.Content); for (auto & comp : Definitions) if (comp->Implementation->ExportWorlds.Contains(comp->World) || Shader->Pipeline->IsAbstractWorld(comp->World) && (comp->Implementation->SyntaxNode->LayoutAttributes.ContainsKey(L"Pinned") || Shader->Pipeline->Worlds[comp->World]().SyntaxNode->LayoutAttributes.ContainsKey(L"Pinned"))) { comp->IsEntryPoint = true; } List<ComponentDefinitionIR*> workList; HashSet<ComponentDefinitionIR*> referencedDefs; for (auto & def : Definitions) { if (def->IsEntryPoint) { if (referencedDefs.Add(def.Ptr())) workList.Add(def.Ptr()); } } for (int i = 0; i < workList.Count(); i++) { auto def = workList[i]; for (auto & dep : def->Dependency) { if (referencedDefs.Add(dep)) workList.Add(dep); } } List<RefPtr<ComponentDefinitionIR>> newDefinitions; for (auto & def : Definitions) { if (referencedDefs.Contains(def.Ptr())) { newDefinitions.Add(def); EnumerableHashSet<ComponentDefinitionIR*> newSet; for (auto & comp : def->Users) if (referencedDefs.Contains(comp)) { newSet.Add(comp); } def->Users = newSet; newSet.Clear(); for (auto & comp : def->Dependency) if (referencedDefs.Contains(comp)) { newSet.Add(comp); } def->Dependency = newSet; } } Definitions = _Move(newDefinitions); for (auto & kv : DefinitionsByComponent) { for (auto & def : kv.Value) if (!referencedDefs.Contains(def.Value)) kv.Value.Remove(def.Key); } }
virtual void Compile(CompileResult & result, CompilationContext & context, List<CompileUnit> & units, const CompileOptions & options) override { RefPtr<ProgramSyntaxNode> programSyntaxNode = new ProgramSyntaxNode(); for (auto & unit : units) { programSyntaxNode->Include(unit.SyntaxNode.Ptr()); } SymbolTable & symTable = context.Symbols; auto & shaderClosures = context.ShaderClosures; RefPtr<SyntaxVisitor> visitor = CreateSemanticsVisitor(&symTable, result.GetErrorWriter()); try { programSyntaxNode->Accept(visitor.Ptr()); if (result.GetErrorCount() > 0) return; // if user specified a template shader symbol, instantiate the template now String symbolToCompile = options.SymbolToCompile; if (symbolToCompile.Length()) { auto templateShaders = programSyntaxNode->GetMembersOfType<TemplateShaderSyntaxNode>(); for (auto & ts : templateShaders) if (ts->Name.Content == symbolToCompile) { auto shader = InstantiateShaderTemplate(result.GetErrorWriter(), &symTable, ts.Ptr(), options.TemplateShaderArguments); if (shader) { programSyntaxNode->Members.Add(shader); symbolToCompile = shader->Name.Content; programSyntaxNode->Accept(visitor.Ptr()); } break; } } visitor = nullptr; symTable.EvalFunctionReferenceClosure(); if (result.GetErrorCount() > 0) return; for (auto & shader : symTable.ShaderDependenceOrder) { if (shader->IsAbstract) continue; if (!shaderClosures.ContainsKey(shader->SyntaxNode->Name.Content)) { auto shaderClosure = CreateShaderClosure(result.GetErrorWriter(), &symTable, shader); FlattenShaderClosure(result.GetErrorWriter(), &symTable, shaderClosure.Ptr()); shaderClosures.Add(shader->SyntaxNode->Name.Content, shaderClosure); } } ResolveAttributes(&symTable); if (result.GetErrorCount() > 0) return; CodeGenBackend * backend = nullptr; switch(options.Target) { case CodeGenTarget::SPIRV: backend = backends["spirv"]().Ptr(); break; case CodeGenTarget::GLSL: backend = backends["glsl"]().Ptr(); break; case CodeGenTarget::GLSL_Vulkan: backend = backends["glsl_vk"]().Ptr(); break; case CodeGenTarget::GLSL_Vulkan_OneDesc: backend = backends["glsl_vk_onedesc"]().Ptr(); break; case CodeGenTarget::HLSL: backend = backends["hlsl"]().Ptr(); break; default: // TODO: emit an appropriate diagnostic return; } Schedule schedule; if (options.ScheduleSource != "") { schedule = Schedule::Parse(options.ScheduleSource, options.ScheduleFileName, result.GetErrorWriter()); } for (auto shader : shaderClosures) { // generate shader variant from schedule file, and also apply mechanic deduction rules if (!shader.Value->IR) shader.Value->IR = GenerateShaderVariantIR(result, shader.Value.Ptr(), schedule, &symTable); } if (options.Mode == CompilerMode::ProduceShader) { if (result.GetErrorWriter()->GetErrorCount() > 0) return; // generate IL code RefPtr<ICodeGenerator> codeGen = CreateCodeGenerator(&symTable, result); if (context.Program) { result.Program->Functions = context.Program->Functions; result.Program->Shaders = context.Program->Shaders; result.Program->Structs = context.Program->Structs; result.Program->ConstantPool = context.Program->ConstantPool; } for (auto & s : programSyntaxNode->GetStructs()) codeGen->ProcessStruct(s.Ptr()); for (auto & func : programSyntaxNode->GetFunctions()) codeGen->ProcessFunction(func.Ptr()); for (auto & shader : shaderClosures) { InsertImplicitImportOperators(result.GetErrorWriter(), shader.Value->IR.Ptr()); } if (result.GetErrorCount() > 0) return; for (auto & shader : shaderClosures) { codeGen->ProcessShader(shader.Value->IR.Ptr()); } if (result.GetErrorCount() > 0) return; // emit target code EnumerableHashSet<String> symbolsToGen; for (auto & unit : units) { for (auto & shader : unit.SyntaxNode->GetShaders()) if (!shader->IsModule) symbolsToGen.Add(shader->Name.Content); for (auto & func : unit.SyntaxNode->GetFunctions()) symbolsToGen.Add(func->Name.Content); } auto IsSymbolToGen = [&](String & shaderName) { if (symbolsToGen.Contains(shaderName)) return true; for (auto & symbol : symbolsToGen) if (shaderName.StartsWith(symbol)) return true; return false; }; for (auto & shader : result.Program->Shaders) { if ((symbolToCompile.Length() == 0 && IsSymbolToGen(shader->Name)) || EscapeCodeName(symbolToCompile) == shader->Name) { StringBuilder glslBuilder; Dictionary<String, String> targetCode; result.CompiledSource[shader->Name] = backend->GenerateShader(result, &symTable, shader.Ptr(), result.GetErrorWriter()); } } } else if (options.Mode == CompilerMode::GenerateChoice) { for (auto shader : shaderClosures) { if (options.SymbolToCompile.Length() == 0 || shader.Value->Name == options.SymbolToCompile) { auto &worldOrder = shader.Value->Pipeline->GetWorldTopologyOrder(); for (auto & comp : shader.Value->AllComponents) { ShaderChoice choice; if (comp.Value.Symbol->ChoiceNames.Count() == 0) continue; if (comp.Value.Symbol->IsRequire()) continue; choice.ChoiceName = comp.Value.Symbol->ChoiceNames.First(); for (auto & impl : comp.Value.Symbol->Implementations) { for (auto w : impl->Worlds) if (comp.Value.Symbol->Type->ConstrainedWorlds.Contains(w)) choice.Options.Add(ShaderChoiceValue(w)); } if (auto defs = shader.Value->IR->DefinitionsByComponent.TryGetValue(comp.Key)) { int latestWorldOrder = -1; for (auto & def : *defs) { int order = worldOrder.IndexOf(def.Key); if (latestWorldOrder < order) { choice.DefaultValue = def.Key; latestWorldOrder = order; } } } result.Choices.Add(choice); } } } } else { result.GetErrorWriter()->diagnose(CodePosition(), Diagnostics::unsupportedCompilerMode); return; } context.Program = result.Program; } catch (int) { } catch (...) { throw; } return; }