Skip to content

[REFACTOR][SCRIPT] Move script_printer.h → script/printer/config.h; rename TVM_SCRIPT_REPR; replace dialect fields with extra_config#19478

Closed
tqchen wants to merge 1 commit into
apache:mainfrom
tqchen:tvm-script-printer-config
Closed

[REFACTOR][SCRIPT] Move script_printer.h → script/printer/config.h; rename TVM_SCRIPT_REPR; replace dialect fields with extra_config#19478
tqchen wants to merge 1 commit into
apache:mainfrom
tqchen:tvm-script-printer-config

Conversation

@tqchen

@tqchen tqchen commented Apr 29, 2026

Copy link
Copy Markdown
Member

Summary

include/tvm/ir/script_printer.h placed PrinterConfig and TVMScriptPrinter under tvm/ir/ — these are printer-layer concepts, not IR-specific. Move to include/tvm/script/printer/config.h alongside the printer's other public headers (doc.h, ir_docsifier.h, ir_docsifier_functor.h).

  • Rename TVM_SCRIPT_REPRTVM_REGISTER_SCRIPT_AS_REPR: the macro registers Script as the kRepr callback for an object type and installs the per-type TVMScriptPrinter::vtable() dispatch entry. The new name is explicit about the registration semantic and aligns with the TVM_REGISTER_* family.

  • Drop dialect-specific PrinterConfig fields (tir_prefix, relax_prefix, show_all_struct_info, buffer_dtype) in favor of a generic ffi::Map<String, Any> extra_config keyed by "<dialect>.<knob>" (e.g. "tirx.prefix", "relax.show_all_struct_info"). Each dialect reads its own keys via GetExtraConfig<T>(key, fallback) with defaults at the call site; the shared core never names a specific dialect through hard-coded fields. ir_prefix and module_alias also flip from std::string to ffi::String for consistency. RedirectedReprPrinterMethod is de-inlined into src/script/printer/config.cc to keep <tvm/runtime/logging.h> out of the public header.

  • ~6 header includers and ~80 macro use sites updated; Python config wrappers updated to write into extra_config with dotted keys.

…ename TVM_SCRIPT_REPR; replace dialect fields with extra_config

include/tvm/ir/script_printer.h misplaced PrinterConfig and
TVMScriptPrinter under tvm/ir/ — these are printer-layer concepts,
not IR-specific.  Move to include/tvm/script/printer/config.h next
to the rest of the printer's public surface (doc.h, ir_docsifier.h,
ir_docsifier_functor.h).

Rename TVM_SCRIPT_REPR → TVM_REGISTER_SCRIPT_AS_REPR for clarity:
the macro registers Script as the kRepr callback for an object
type plus a per-type TVMScriptPrinter::vtable() dispatch entry.
The new name is explicit about the registration semantic and
aligns with the TVM_REGISTER_* family.

Drop hard-coded dialect-specific fields from PrinterConfig
(tir_prefix, relax_prefix, show_all_struct_info, buffer_dtype) in
favor of a generic ffi::Map<String, Any> extra_config keyed by
"<dialect>.<knob>" (e.g. "tirx.prefix", "relax.show_all_struct_info").
Each dialect reads its own keys via GetExtraConfig<T>(key, fallback)
with defaults at the call site; the shared core never names a specific
dialect through hardcoded fields.  ir_prefix and module_alias also
flip from std::string to ffi::String for consistency with the rest
of the config.  RedirectedReprPrinterMethod is de-inlined into a
new src/script/printer/config.cc to keep <tvm/runtime/logging.h>
out of the public header.

~6 header includers + ~80 macro use sites updated; Python config
wrappers updated to write into extra_config with dotted keys.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the PrinterConfig by moving it to a new header and replacing dialect-specific fields with a generic extra_config map to improve decoupling. It introduces a GetExtraConfig helper for accessing these settings and updates the script representation registration macro. Feedback highlights that GetExtraConfig incorrectly uses Downcast for POD types and that the configuration constructor still contains hardcoded dialect-specific logic, which should be generalized to fully achieve the architectural goals.

T GetExtraConfig(const ffi::String& key, T fallback) const {
auto it = extra_config.find(key);
if (it == extra_config.end()) return fallback;
return Downcast<T>((*it).second);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of Downcast<T> here is incorrect for non-ObjectRef types. Since extra_config stores ffi::Any values, and this method is used with types like bool (in binding.cc) and DataType (in buffer.cc), Downcast will fail to compile or error at runtime for these POD-like types. Using ffi::Any::cast<T>() is the correct way to retrieve values from an Any container generically.

    return (*it).second.cast<T>();

Comment thread src/ir/script_printer.cc
Comment on lines +119 to +132
for (const char* key : {"tirx.prefix", "relax.prefix"}) {
if (auto v = config_dict.Get(key)) {
n->extra_config.Set(ffi::String(key), v.value());
}
}
// "tirx.buffer_dtype" is passed as a DLDataType string from Python; convert to DataType.
if (auto v = config_dict.Get("tirx.buffer_dtype")) {
DataType dt(ffi::StringToDLDataType(Downcast<ffi::String>(v.value())));
n->extra_config.Set(ffi::String("tirx.buffer_dtype"), ffi::Any(dt));
}
// Boolean dialect keys.
if (auto v = config_dict.Get("relax.show_all_struct_info")) {
n->extra_config.Set(ffi::String("relax.show_all_struct_info"), v.value());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation here contradicts the architectural goal stated in the PR description: "shared core never names a specific dialect through hard-coded fields." This constructor still contains hardcoded logic for tirx and relax dialects, including specific key mapping and DataType conversion for tirx.buffer_dtype. To achieve true decoupling, this logic should be generalized (e.g., by iterating over all non-core keys in config_dict) or moved to a registration-based system where dialects can define their own configuration conversion and validation logic.

@tqchen tqchen closed this Apr 29, 2026
@tqchen

tqchen commented Apr 29, 2026

Copy link
Copy Markdown
Member Author

Folded into #19479 — single coherent TVMScript dialect-friendly refactor PR. Commits absorbed; this PR's branch can be deleted.

tqchen added a commit that referenced this pull request Apr 30, 2026
…estructure + dialect registry (#19479)

## Summary

Restructure TVMScript to be dialect-agnostic at the script-core layer
while letting each extension dialect (TIRX, Relax) own its own
per-dialect script subtree.  IR is below script in the dependency
stack and is NOT a peer dialect — its script handlers stay in the
shared core.

This PR folds together two coupled refactors that were initially
opened as separate PRs (#19478 and the original #19479); they
share rename / relocation surface so they ship as one cohesive
change.

## What this PR does

### Per-dialect script subtree (originally #19479)

- Moves per-dialect printer + builder from
  `src/script/{printer,ir_builder}/{tirx,relax}/` to
  `src/{tirx,relax}/script/{printer,builder}/`.
- Tightens `src/script/*.cc` CMake glob to the dialect-free core.
- Refactors `IRBuilder::DeclFunction` to dispatch via FFI registry
  (`script.ir_builder.decl_function.<type-key>`); removes
  cross-dialect includes from the shared core.
- Adds `tvm.script.register_dialect` API + `__getattr__` + a
  `sys.meta_path` finder for Python-side dialect discovery.
  In-tree dialects (tirx, relax) registered centrally in
  `python/tvm/__init__.py`.
- Drops the obsolete static re-export shims at
  `python/tvm/script/{parser,ir_builder}/{tirx,relax}/`.

### Dialect-agnostic printer config (originally #19478)

- Relocates `include/tvm/ir/script_printer.h` →
  `include/tvm/script/printer/config.h` next to the rest of the
  printer's public surface.  The header is not IR-specific.
- Renames `TVM_SCRIPT_REPR` → `TVM_REGISTER_SCRIPT_AS_REPR` for
  clarity (the macro registers Script as the kRepr callback +
  per-type vtable dispatch).  Aligns with the `TVM_REGISTER_*`
  family.
- Drops dialect-hardcoded `PrinterConfig` fields (`tir_prefix`,
  `relax_prefix`, `show_all_struct_info`, `buffer_dtype`) in favor
  of a generic `ffi::Map<String, Any> extra_config` keyed by
  `"<dialect>.<knob>"`.  Each call site reads via the templated
  accessor `config->GetExtraConfig<T>("...", default)`.
- Promotes `std::string` config fields to `ffi::String`.

After this lands, the script-printer core knows nothing specific
about any dialect — new dialects plug in via the registry pattern
with zero core edits.  Public Python API surface unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant