mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:40:11 +01:00
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:
+26
-2
@@ -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:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user