Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -568,25 +568,76 @@ return Var; } -/// Determine whether a variable appears in a count: expression. -static bool dependsOn(DbgVariable *A, DbgVariable *B) { - auto *Array = dyn_cast(A->getType()); +/// Return all DIVariables that appear in count: expressions. +static SmallVector dependencies(DbgVariable *Var) { + SmallVector Result; + auto *Array = dyn_cast(Var->getType()); if (!Array || Array->getTag() != dwarf::DW_TAG_array_type) - return false; - return llvm::any_of(Array->getElements(), [&](DINode *El) { + return Result; + for (auto *El : Array->getElements()) { if (auto *Subrange = dyn_cast(El)) { auto Count = Subrange->getCount(); - if (auto *Var = Count.dyn_cast()) - return Var == B->getVariable(); + if (auto *Dependency = Count.dyn_cast()) + Result.push_back(Dependency); } - return false; - }); + } + return Result; } /// Sort local variables so that variables appearing inside of helper /// expressions come first. -static bool sortLocalVars(DbgVariable *A, DbgVariable *B) { - return dependsOn(B, A); +static SmallVector sortLocalVars(SmallVectorImpl &Input) { + SmallVector Result; + SmallVector, 8> WorkList; + /// Map back from a DIVariable to its containing DbgVariable. + SmallDenseMap DbgVar; + /// Set of DbgVariables in Result. + SmallDenseSet Visited(WorkList.size()); + /// For cycle detection. + SmallDenseSet Visiting(WorkList.size()); + for (auto N : reverse(Input)) { + DbgVar.insert({N->getVariable(), N}); + WorkList.push_back({N, 0}); + } + // Perform a stable topological sort by doing a DFS. + while (!WorkList.empty()) { + auto Item = WorkList.back(); + DbgVariable *N = Item.getPointer(); + bool visitedAllDependencies = Item.getInt(); + + WorkList.pop_back(); + + assert(N && "dependency is in a different lexical scope"); + if (!N) + continue; + + // Already handled. + if (Visited.count(N)) + continue; + + // Add to Result if all dependencies are visited. + if (visitedAllDependencies) { + Visited.insert(N); + Result.push_back(N); + continue; + } + + // Detect cycles. + auto Res = Visiting.insert(N); + if (!Res.second) { + assert(false && "dependency cycle in local variables"); + return Result; + } + + // Push dependencies and this node onto the worklist, so that this node is + // visited again after all of its dependencies are handled. + WorkList.push_back({N, 1}); + for (auto *Dependency : dependencies(N)) { + auto Var = dyn_cast_or_null(Dependency); + WorkList.push_back({DbgVar[Var], 0}); + } + } + return Result; } DIE *DwarfCompileUnit::createScopeChildrenDIE(LexicalScope *Scope, @@ -601,8 +652,8 @@ Children.push_back(constructVariableDIE(*DV.second, *Scope, ObjectPointer)); // Emit local variables. - std::stable_sort(Vars.Locals.begin(), Vars.Locals.end(), sortLocalVars); - for (DbgVariable *DV : Vars.Locals) + auto Locals = sortLocalVars(Vars.Locals); + for (DbgVariable *DV : Locals) Children.push_back(constructVariableDIE(*DV, *Scope, ObjectPointer)); // Skip imported directives in gmlt-like data.