@@ -218,27 +218,62 @@ void DIBuilder::SetValue(Loc loc, llvm::Value *value,
218218 IR->scopebb ());
219219}
220220
221+ std::string DIBuilder::remapDIPath (llvm::StringRef path) {
222+ for (const auto &[from, to] : opts::debugPrefixMap) {
223+ if (path.startswith (from)) {
224+ return to + path.substr (from.size ()).str ();
225+ }
226+ }
227+ return std::string (path);
228+ }
229+
221230DIFile DIBuilder::CreateFile (const char *filename) {
222231 if (!filename)
223232 filename = IR->dmodule ->srcfile .toChars ();
224233
225- // clang appears to use the curent working dir as 'directory' for relative
226- // source paths, and the root path for absolute ones:
227- // clang -g -emit-llvm -S ..\blub.c =>
228- // !DIFile(filename: "..\\blub.c", directory: "C:\\LDC\\ninja-ldc", ...)
229- // !DIFile(filename: "Program
230- // Files\\LLVM\\lib\\clang\\11.0.1\\include\\stddef.h", directory: "C:\\",
231- // ...)
232-
233- if (llvm::sys::path::is_absolute (filename)) {
234- return DBuilder.createFile (llvm::sys::path::relative_path (filename),
235- llvm::sys::path::root_path (filename));
236- }
234+ // Mimic clang's behavior as much as possible, including fdebug-prefix-map
235+ // remap behavior. See LLVM source clang/lib/CodeGen/CGDebugInfo.cpp
236+
237+ auto remappedFile = remapDIPath (filename);
237238
238239 llvm::SmallString<128 > cwd;
239240 llvm::sys::fs::current_path (cwd);
241+ auto currentDir = remapDIPath (cwd);
242+
243+ llvm::StringRef debuginfoDir;
244+ llvm::StringRef debuginfoFile;
245+
246+ llvm::SmallString<128 > DirBuf;
247+ llvm::SmallString<128 > FileBuf;
248+ if (llvm::sys::path::is_absolute (remappedFile)) {
249+ // Strip the common prefix (if it is more than just "/" or "C:\") from
250+ // current directory and filename for a more space-efficient encoding.
251+ auto FileIt = llvm::sys::path::begin (remappedFile);
252+ auto FileE = llvm::sys::path::end (remappedFile);
253+ auto CurDirIt = llvm::sys::path::begin (currentDir);
254+ auto CurDirE = llvm::sys::path::end (currentDir);
255+ for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt)
256+ llvm::sys::path::append (DirBuf, *CurDirIt);
257+ if (llvm::sys::path::root_path (DirBuf) == DirBuf) {
258+ // Don't strip the common prefix if it is only the root ("/" or "C:\")
259+ // since that would make diagnostic locations confusing.
260+ debuginfoDir = {};
261+ debuginfoFile = remappedFile;
262+ } else {
263+ for (; FileIt != FileE; ++FileIt)
264+ llvm::sys::path::append (FileBuf, *FileIt);
265+ debuginfoDir = DirBuf;
266+ debuginfoFile = FileBuf;
267+ }
268+ } else {
269+ if (!llvm::sys::path::is_absolute (filename))
270+ debuginfoDir = currentDir;
271+ debuginfoFile = remappedFile;
272+ }
240273
241- return DBuilder.createFile (filename, cwd);
274+ // TODO: If debug file creation turns out to cost a lot of time, implement a
275+ // caching mechanism like clang does.
276+ return DBuilder.createFile (debuginfoFile, debuginfoDir);
242277}
243278
244279DIFile DIBuilder::CreateFile (Loc loc) {
0 commit comments