Add --dump-sem-ir-ranges for controlling dump output (#5450)

Right now, a lot of tests have started setting `--no-dump-sem-ir`. My
thought is that we can look at:

1. Put ranges in a bunch more files.
2. Shift more towards `--dump-sem-ir-ranges=only` instead of
`--no-dump-sem-ir`, because it allows mixing fail-tests with no IR
alongside tests that contain IR.
3. Evaluate switching the default to `--dump-sem-ir-ranges=only`, and
instead set `--dump-sem-ir-ranges=if-present` only in files that want to
typically show all IR (particularly import-related tests, where ranges
don't work well).

In real-world use, my thought is also that it'd be helpful to be able to
add the dump range comments to files, see the output (i.e., the default
behavior of `if-present`) but then also be able to pass `ignore` in
order to see the full IR without modifying the file (possibly also
useful in tests). That model is why I went for tri-state handling.

Note `only` can also have an interesting side-effect. Because core files
(including min_prelude versions) typically won't have ranges, they'd be
implicitly excluded.
This commit is contained in:
Jon Ross-Perkins
2025-05-12 14:51:10 +00:00
committed by GitHub
parent b6a55c0818
commit 937caaecce
7 changed files with 194 additions and 22 deletions
@@ -2,11 +2,13 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// The default behavior should be `--dump-sem-ir-ranges=if-present`.
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_range.carbon
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_range.carbon
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges.carbon
// --- function.carbon
@@ -78,6 +80,12 @@ fn G() {
);
}
// --- file_without_ranges.carbon
library "[[@TEST_NAME]]";
fn F();
// CHECK:STDOUT: --- function.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -181,3 +189,19 @@ fn G() {
// CHECK:STDOUT: %.loc17_7.3: %empty_tuple.type = converted %C.call, %tuple.loc17 [concrete = constants.%empty_tuple]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- file_without_ranges.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F();
// CHECK:STDOUT:
@@ -0,0 +1,58 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --dump-sem-ir-ranges=ignore
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges_ignore.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges_ignore.carbon
// --- with-range.carbon
library "[[@TEST_NAME]]";
//@dump-sem-ir-begin
fn F();
//@dump-sem-ir-end
// --- without-range.carbon
library "[[@TEST_NAME]]";
fn F();
// CHECK:STDOUT: --- with-range.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F();
// CHECK:STDOUT:
// CHECK:STDOUT: --- without-range.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F();
// CHECK:STDOUT:
@@ -0,0 +1,37 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// EXTRA-ARGS: --dump-sem-ir-ranges=only
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges_only.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/basics/no_prelude/dump_sem_ir_ranges_only.carbon
// --- with-range.carbon
library "[[@TEST_NAME]]";
//@dump-sem-ir-begin
fn F();
//@dump-sem-ir-end
// --- without-range.carbon
library "[[@TEST_NAME]]";
fn F();
// CHECK:STDOUT: --- with-range.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F();
// CHECK:STDOUT:
+54 -14
View File
@@ -180,10 +180,32 @@ Dump the raw JSON structure of SemIR to stdout when built.
{
.name = "dump-sem-ir",
.help = R"""(
Dump the SemIR to stdout when built.
Dump the full SemIR to stdout when built.
)""",
},
[&](auto& arg_b) { arg_b.Set(&dump_sem_ir); });
b.AddOneOfOption(
{
.name = "dump-sem-ir-ranges",
.help = R"""(
Selects handling of `//@dump-sem-ir-[begin|end]` markers when dumping SemIR.
By default, `if-present` prints ranges for files that have them, and full SemIR
for files that don't. `only` skips files with no ranges, and `ignore` always
prints full SemIR.
)""",
},
[&](auto& arg_b) {
arg_b.SetOneOf(
{
arg_b.OneOfValue("if-present", DumpSemIRRanges::IfPresent)
.Default(true),
arg_b.OneOfValue("only", DumpSemIRRanges::Only),
arg_b.OneOfValue("ignore", DumpSemIRRanges::Ignore),
},
&dump_sem_ir_ranges);
});
b.AddFlag(
{
.name = "builtin-sem-ir",
@@ -399,6 +421,9 @@ class CompilationUnit {
// significant overhead. Avoid constructing it when unused.
auto GetParseTreeAndSubtrees() -> const Parse::TreeAndSubtrees&;
// Handles printing of formatted SemIR.
auto MaybePrintFormattedSemIR() -> void;
// Wraps a call with log statements to indicate start and end. Typically logs
// with the actual function name, but marks timings with the appropriate
// phase.
@@ -624,6 +649,33 @@ auto CompilationUnit::GetCheckUnit() -> Check::Unit {
.cpp_ast = &cpp_ast_};
}
auto CompilationUnit::MaybePrintFormattedSemIR() -> void {
bool print = options_->dump_sem_ir && IncludeInDumps();
if (!vlog_stream_ && !print) {
return;
}
if (options_->dump_sem_ir_ranges == CompileOptions::DumpSemIRRanges::Only &&
!tokens_->has_dump_sem_ir_ranges()) {
return;
}
bool use_dump_sem_ir_ranges =
options_->dump_sem_ir_ranges != CompileOptions::DumpSemIRRanges::Ignore &&
tokens_->has_dump_sem_ir_ranges();
SemIR::Formatter formatter(&*sem_ir_, *tree_and_subtrees_getter_,
cache_->include_in_dumps(),
use_dump_sem_ir_ranges);
formatter.Format();
if (vlog_stream_) {
CARBON_VLOG("*** SemIR::File ***\n");
formatter.Write(*vlog_stream_);
}
if (print) {
formatter.Write(*driver_env_->output_stream);
}
}
auto CompilationUnit::PostCheck() -> void {
CARBON_CHECK(sem_ir_, "Must call GetCheckUnit first");
@@ -644,19 +696,7 @@ auto CompilationUnit::PostCheck() -> void {
}
}
bool print = options_->dump_sem_ir && IncludeInDumps();
if (vlog_stream_ || print) {
SemIR::Formatter formatter(&*sem_ir_, *tree_and_subtrees_getter_,
cache_->include_in_dumps());
formatter.Format();
if (vlog_stream_) {
CARBON_VLOG("*** SemIR::File ***\n");
formatter.Write(*vlog_stream_);
}
if (print) {
formatter.Write(*driver_env_->output_stream);
}
}
MaybePrintFormattedSemIR();
if (sem_ir_->has_errors()) {
success_ = false;
}
+7
View File
@@ -28,6 +28,12 @@ struct CompileOptions {
CodeGen,
};
enum class DumpSemIRRanges : int8_t {
IfPresent,
Only,
Ignore,
};
friend auto operator<<(llvm::raw_ostream& out, Phase phase)
-> llvm::raw_ostream&;
@@ -36,6 +42,7 @@ struct CompileOptions {
CodegenOptions codegen_options;
Phase phase;
DumpSemIRRanges dump_sem_ir_ranges;
llvm::StringRef output_filename;
llvm::SmallVector<llvm::StringRef> input_filenames;
+7 -5
View File
@@ -34,17 +34,19 @@ namespace Carbon::SemIR {
Formatter::Formatter(const File* sem_ir,
Parse::GetTreeAndSubtreesFn get_tree_and_subtrees,
llvm::ArrayRef<bool> include_ir_in_dumps)
llvm::ArrayRef<bool> include_ir_in_dumps,
bool use_dump_sem_ir_ranges)
: sem_ir_(sem_ir),
inst_namer_(sem_ir_),
get_tree_and_subtrees_(get_tree_and_subtrees),
include_ir_in_dumps_(include_ir_in_dumps) {
include_ir_in_dumps_(include_ir_in_dumps),
use_dump_sem_ir_ranges_(use_dump_sem_ir_ranges) {
// Create a placeholder visible chunk and assign it to all instructions that
// don't have a chunk of their own.
auto first_chunk = AddChunkNoFlush(true);
tentative_inst_chunks_.resize(sem_ir_->insts().size(), first_chunk);
if (sem_ir_->parse_tree().tokens().has_dump_sem_ir_ranges()) {
if (use_dump_sem_ir_ranges_) {
ComputeNodeParents();
}
@@ -184,7 +186,7 @@ auto Formatter::ShouldFormatEntity(InstId decl_id, bool is_definition_start)
return false;
}
if (!sem_ir_->parse_tree().tokens().has_dump_sem_ir_ranges()) {
if (!use_dump_sem_ir_ranges_) {
return true;
}
@@ -224,7 +226,7 @@ auto Formatter::ShouldFormatEntity(const EntityWithParamsBase& entity) -> bool {
}
auto Formatter::ShouldFormatInst(InstId inst_id) -> bool {
if (!sem_ir_->parse_tree().tokens().has_dump_sem_ir_ranges()) {
if (!use_dump_sem_ir_ranges_) {
return true;
}
+5 -1
View File
@@ -19,7 +19,8 @@ class Formatter {
public:
explicit Formatter(const File* sem_ir,
Parse::GetTreeAndSubtreesFn get_tree_and_subtrees,
llvm::ArrayRef<bool> include_ir_in_dumps);
llvm::ArrayRef<bool> include_ir_in_dumps,
bool use_dump_sem_ir_ranges);
// Prints the SemIR into an internal buffer.
//
@@ -327,6 +328,9 @@ class Formatter {
// For each CheckIRId, whether entities from it should be formatted.
llvm::ArrayRef<bool> include_ir_in_dumps_;
// Whether to use ranges when dumping, or to dump the full SemIR.
bool use_dump_sem_ir_ranges_;
// The output stream buffer.
std::string buffer_;