[FIRRTL] AssignOutputDirs: Ensure absolute dirs end with trailing slash (#7348)

When making a directory absolute, the remove_dots helper canonicalizes away any
trailing slash. Add the slash back on, which ensures that we interpret the path
as a directory correctly.

This fixes a bug where a path, when LCA'd with itself, drops the last segment.

An example of the problem: given a path foo/bar/, if we drop the trailing
slash, foo/bar is interpreted as a file called bar in a directory called foo.
When we LCA foo/bar with itself, the common parent directory is determined to
be foo/. By retaining the trailing slash, we can ensure that the correct LCA
path foo/bar/ is computed.

Fixes: #7347
This commit is contained in:
Robert Young 2024-07-18 21:26:49 -04:00 committed by GitHub
parent 52e7c2e355
commit 7c8a2e195a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 40 additions and 1 deletions

View File

@ -38,8 +38,12 @@ using hw::OutputFileAttr;
// interpreting moduleOutputDir as relative to the outputDir.
static void makeAbsolute(StringRef outputDir,
SmallString<64> &moduleOutputDir) {
auto sep = llvm::sys::path::get_separator();
if (!moduleOutputDir.empty())
assert(moduleOutputDir.ends_with(sep));
fs::make_absolute(outputDir, moduleOutputDir);
path::remove_dots(moduleOutputDir, true);
moduleOutputDir += sep;
}
// If outputDir is a prefix of moduleOutputDir, then make moduleOutputDir
@ -69,7 +73,7 @@ static void makeCommonPrefix(SmallString<64> &a, StringRef b) {
static void makeCommonPrefix(StringRef outputDir, SmallString<64> &a,
OutputFileAttr attr) {
if (attr) {
SmallString<64> b(attr.getFilename());
SmallString<64> b(attr.getDirectory());
makeAbsolute(outputDir, b);
makeCommonPrefix(a, b);
} else {

View File

@ -93,3 +93,38 @@ firrtl.circuit "AssignOutputDirs" {
firrtl.instance byYZ @ByYZ()
}
}
// https://github.com/llvm/circt/issues/7347
firrtl.circuit "SameOutputDirTwice" {
// CHECK: firrtl.module private @Bar() attributes {output_file = #hw.output_file<"verification{{/|\\\\}}testbench{{/|\\\\}}">} {
firrtl.module private @Bar() {
}
firrtl.module @Foo() attributes {output_file = #hw.output_file<"verification/testbench/">} {
firrtl.instance bar1 @Bar()
firrtl.instance bar2 @Bar()
}
firrtl.module @SameOutputDirTwice() {}
}
firrtl.circuit "EmptyOutputDir" {
// CHECK: firrtl.module private @Bar() {
firrtl.module private @Bar() {
}
firrtl.module @Foo() attributes {output_file = #hw.output_file<"some_file">} {
firrtl.instance bar1 @Bar()
}
firrtl.module @EmptyOutputDir() {}
}
firrtl.circuit "EmptyOutputDir2" {
// CHECK: firrtl.module private @Baz() attributes {output_file = #hw.output_file<"{{/|\\\\}}path{{/|\\\\}}to{{/|\\\\}}">} {
firrtl.module private @Baz() {
}
firrtl.module @Foo() attributes {output_file = #hw.output_file<"some_file">} {
firrtl.instance baz @Baz()
}
firrtl.module @Bar() attributes {output_file = #hw.output_file<"/path/to/">} {
firrtl.instance baz @Baz()
}
firrtl.module @EmptyOutputDir2() {}
}