|
13 | 13 | #include "llvm/IR/DebugInfoMetadata.h" |
14 | 14 | #include "LLVMContextImpl.h" |
15 | 15 | #include "MetadataImpl.h" |
16 | | -#include "llvm/ADT/SmallPtrSet.h" |
| 16 | +#include "llvm/ADT/SetVector.h" |
17 | 17 | #include "llvm/ADT/StringSwitch.h" |
18 | 18 | #include "llvm/BinaryFormat/Dwarf.h" |
19 | 19 | #include "llvm/IR/DebugProgramInstruction.h" |
@@ -125,6 +125,98 @@ DILocation *DILocation::getMergedLocations(ArrayRef<DILocation *> Locs) { |
125 | 125 | return Merged; |
126 | 126 | } |
127 | 127 |
|
| 128 | +static DILexicalBlockBase *cloneAndReplaceParentScope(DILexicalBlockBase *LBB, |
| 129 | + DIScope *NewParent) { |
| 130 | + TempMDNode ClonedScope = LBB->clone(); |
| 131 | + cast<DILexicalBlockBase>(*ClonedScope).replaceScope(NewParent); |
| 132 | + return cast<DILexicalBlockBase>( |
| 133 | + MDNode::replaceWithUniqued(std::move(ClonedScope))); |
| 134 | +} |
| 135 | + |
| 136 | +using LineColumn = std::pair<unsigned /* Line */, unsigned /* Column */>; |
| 137 | + |
| 138 | +/// Returns the location of DILocalScope, if present, or a default value. |
| 139 | +static LineColumn getLocalScopeLocationOr(DIScope *S, LineColumn Default) { |
| 140 | + assert(isa<DILocalScope>(S) && "Expected DILocalScope."); |
| 141 | + |
| 142 | + if (isa<DILexicalBlockFile>(S)) |
| 143 | + return Default; |
| 144 | + if (auto *LB = dyn_cast<DILexicalBlock>(S)) |
| 145 | + return {LB->getLine(), LB->getColumn()}; |
| 146 | + if (auto *SP = dyn_cast<DISubprogram>(S)) |
| 147 | + return {SP->getLine(), 0u}; |
| 148 | + |
| 149 | + llvm_unreachable("Unhandled type of DILocalScope."); |
| 150 | +} |
| 151 | + |
| 152 | +// Returns the nearest matching scope inside a subprogram. |
| 153 | +template <typename MatcherT> |
| 154 | +static std::pair<DIScope *, LineColumn> |
| 155 | +getNearestMatchingScope(const DILocation *L1, const DILocation *L2) { |
| 156 | + MatcherT Matcher; |
| 157 | + |
| 158 | + DIScope *S1 = L1->getScope(); |
| 159 | + DIScope *S2 = L2->getScope(); |
| 160 | + |
| 161 | + LineColumn Loc1(L1->getLine(), L1->getColumn()); |
| 162 | + for (; S1; S1 = S1->getScope()) { |
| 163 | + Loc1 = getLocalScopeLocationOr(S1, Loc1); |
| 164 | + Matcher.insert(S1, Loc1); |
| 165 | + if (isa<DISubprogram>(S1)) |
| 166 | + break; |
| 167 | + } |
| 168 | + |
| 169 | + LineColumn Loc2(L2->getLine(), L2->getColumn()); |
| 170 | + for (; S2; S2 = S2->getScope()) { |
| 171 | + Loc2 = getLocalScopeLocationOr(S2, Loc2); |
| 172 | + |
| 173 | + if (DIScope *S = Matcher.match(S2, Loc2)) |
| 174 | + return std::make_pair(S, Loc2); |
| 175 | + |
| 176 | + if (isa<DISubprogram>(S2)) |
| 177 | + break; |
| 178 | + } |
| 179 | + return std::make_pair(nullptr, LineColumn(L2->getLine(), L2->getColumn())); |
| 180 | +} |
| 181 | + |
| 182 | +// Matches equal scopes. |
| 183 | +struct EqualScopesMatcher { |
| 184 | + SmallPtrSet<DIScope *, 8> Scopes; |
| 185 | + |
| 186 | + void insert(DIScope *S, LineColumn Loc) { Scopes.insert(S); } |
| 187 | + |
| 188 | + DIScope *match(DIScope *S, LineColumn Loc) { |
| 189 | + return Scopes.contains(S) ? S : nullptr; |
| 190 | + } |
| 191 | +}; |
| 192 | + |
| 193 | +// Matches scopes with the same location. |
| 194 | +struct ScopeLocationsMatcher { |
| 195 | + SmallMapVector<std::pair<DIFile *, LineColumn>, SmallSetVector<DIScope *, 8>, |
| 196 | + 8> |
| 197 | + Scopes; |
| 198 | + |
| 199 | + void insert(DIScope *S, LineColumn Loc) { |
| 200 | + Scopes[{S->getFile(), Loc}].insert(S); |
| 201 | + } |
| 202 | + |
| 203 | + DIScope *match(DIScope *S, LineColumn Loc) { |
| 204 | + auto ScopesAtLoc = Scopes.find({S->getFile(), Loc}); |
| 205 | + // No scope found with the given location. |
| 206 | + if (ScopesAtLoc == Scopes.end()) |
| 207 | + return nullptr; |
| 208 | + |
| 209 | + // Prefer S over other scopes with the same location. |
| 210 | + if (ScopesAtLoc->second.contains(S)) |
| 211 | + return S; |
| 212 | + |
| 213 | + if (!ScopesAtLoc->second.empty()) |
| 214 | + return *ScopesAtLoc->second.begin(); |
| 215 | + |
| 216 | + llvm_unreachable("Scopes must not have empty entries."); |
| 217 | + } |
| 218 | +}; |
| 219 | + |
128 | 220 | DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) { |
129 | 221 | if (!LocA || !LocB) |
130 | 222 | return nullptr; |
@@ -208,28 +300,31 @@ DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) { |
208 | 300 | if (L1->getScope()->getSubprogram() != L2->getScope()->getSubprogram()) |
209 | 301 | return nullptr; |
210 | 302 |
|
211 | | - // Return the nearest common scope inside a subprogram. |
212 | | - auto GetNearestCommonScope = [](DIScope *S1, DIScope *S2) -> DIScope * { |
213 | | - SmallPtrSet<DIScope *, 8> Scopes; |
214 | | - for (; S1; S1 = S1->getScope()) { |
215 | | - Scopes.insert(S1); |
216 | | - if (isa<DISubprogram>(S1)) |
217 | | - break; |
218 | | - } |
219 | | - |
220 | | - for (; S2; S2 = S2->getScope()) { |
221 | | - if (Scopes.count(S2)) |
222 | | - return S2; |
223 | | - if (isa<DISubprogram>(S2)) |
224 | | - break; |
225 | | - } |
226 | | - |
227 | | - return nullptr; |
228 | | - }; |
229 | | - |
230 | | - auto Scope = GetNearestCommonScope(L1->getScope(), L2->getScope()); |
| 303 | + // Find nearest common scope inside subprogram. |
| 304 | + DIScope *Scope = getNearestMatchingScope<EqualScopesMatcher>(L1, L2).first; |
231 | 305 | assert(Scope && "No common scope in the same subprogram?"); |
232 | 306 |
|
| 307 | + // Try using the nearest scope with common location if files are different. |
| 308 | + if (Scope->getFile() != L1->getFile() || L1->getFile() != L2->getFile()) { |
| 309 | + auto [CommonLocScope, CommonLoc] = |
| 310 | + getNearestMatchingScope<ScopeLocationsMatcher>(L1, L2); |
| 311 | + |
| 312 | + // If CommonLocScope is a DILexicalBlockBase, clone it and locate |
| 313 | + // a new scope inside the nearest common scope to preserve |
| 314 | + // lexical blocks structure. |
| 315 | + if (auto *LBB = dyn_cast<DILexicalBlockBase>(CommonLocScope); |
| 316 | + LBB && LBB != Scope) |
| 317 | + CommonLocScope = cloneAndReplaceParentScope(LBB, Scope); |
| 318 | + |
| 319 | + Scope = CommonLocScope; |
| 320 | + |
| 321 | + // If files are still different, assume that L1 and L2 were "included" |
| 322 | + // from CommonLoc. Use it as merged location. |
| 323 | + if (Scope->getFile() != L1->getFile() || L1->getFile() != L2->getFile()) |
| 324 | + return DILocation::get(C, CommonLoc.first, CommonLoc.second, |
| 325 | + CommonLocScope, InlinedAt); |
| 326 | + } |
| 327 | + |
233 | 328 | bool SameLine = L1->getLine() == L2->getLine(); |
234 | 329 | bool SameCol = L1->getColumn() == L2->getColumn(); |
235 | 330 | unsigned Line = SameLine ? L1->getLine() : 0; |
@@ -1187,10 +1282,8 @@ DILocalScope *DILocalScope::cloneScopeForSubprogram( |
1187 | 1282 | // cached result). |
1188 | 1283 | DIScope *UpdatedScope = CachedResult ? CachedResult : &NewSP; |
1189 | 1284 | for (DIScope *ScopeToUpdate : reverse(ScopeChain)) { |
1190 | | - TempMDNode ClonedScope = ScopeToUpdate->clone(); |
1191 | | - cast<DILexicalBlockBase>(*ClonedScope).replaceScope(UpdatedScope); |
1192 | | - UpdatedScope = |
1193 | | - cast<DIScope>(MDNode::replaceWithUniqued(std::move(ClonedScope))); |
| 1285 | + UpdatedScope = cloneAndReplaceParentScope( |
| 1286 | + cast<DILexicalBlockBase>(ScopeToUpdate), UpdatedScope); |
1194 | 1287 | Cache[ScopeToUpdate] = UpdatedScope; |
1195 | 1288 | } |
1196 | 1289 |
|
|
0 commit comments