Skip to content

variables: FLOW_INPUT_VARIANT, read inputs from another variant - #4477

Closed
oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:flow-input-variant
Closed

variables: FLOW_INPUT_VARIANT, read inputs from another variant#4477
oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:flow-input-variant

Conversation

@oharboe

@oharboe oharboe commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

FLOW_VARIANT names the directory a run writes to. It also names the directory a run reads from, so a variant that wants to reuse an upstream variant's results has to physically copy them into its own directory first. Sharing an expensive front end across experiments — one synthesis, one floorplan, many routing variants — is a cp -r per fork today.

The change

FLOW_INPUT_VARIANT names the variant a run reads from, and gives INPUT_RESULTS_DIR, INPUT_LOG_DIR, INPUT_REPORTS_DIR and INPUT_OBJECTS_DIR alongside the existing output directories:

export FLOW_INPUT_VARIANT ?= $(FLOW_VARIANT)
export INPUT_RESULTS_DIR  ?= $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_INPUT_VARIANT)

It defaults to FLOW_VARIANT, so every INPUT_*_DIR expands to a string identical to its *_DIR counterpart and an unchanged run is unchanged.

make DESIGN_CONFIG=... FLOW_VARIANT=base cts
make DESIGN_CONFIG=... FLOW_INPUT_VARIANT=base FLOW_VARIANT=high_effort do-grt do-route do-final

The same mechanism lets one fork produce an input for another — a pin-placement flow running as FLOW_INPUT_VARIANT=base FLOW_VARIANT=io reads the shared floorplan, writes io.tcl into the io variant, and the main flow re-runs from floorplan with IO_CONSTRAINTS pointing at it, still reusing the same base synthesis. docs/user/FlowVariables.md documents this with a diagram.

Search path, not a switch

Reads resolve against RESULTS_DIR first and INPUT_RESULTS_DIR second. That ordering is required, not cosmetic: a stage runs several steps in one process — do-place writes 3_1_place_gp_skip_io.odb and the next step reads it back — so a file this run just wrote must win over the upstream variant's copy. orfs_input_path / orfs_input_glob in util.tcl are the whole mechanism; every write still goes straight to RESULTS_DIR.

What is touched

load_design is the chokepoint — all 18 stage scripts hand it a bare basename, so routing it through orfs_input_path covers the flow. The remaining reads are the AUTO_MEMORIES globs, find_sdc_file, the abstract's .spef, yosys_load's netlist, and genMetrics' log/report/result directories.

find_sdc_file's candidate ordering now compares basenames rather than full paths. With one directory the two are equivalent, since every candidate shares a prefix; with two, the directory prefix would otherwise decide which .sdc wins.

The Makefile's prerequisite graph is deliberately untouched: it still names $(RESULTS_DIR). A forked variant is driven through the do- targets. Teaching the prerequisites to search a second directory is a separate, vpath-shaped change.

Testing

Exercised end to end through bazel-orfs, which is the heaviest user of cross-variant reads — it runs every stage of every design out of one variant's directory into another's, and until now did so by mv-ing inputs before each make. With this patch that renaming is deleted outright and the whole suite (123 tests) passes, so every test in it now runs through this code path.

Added there alongside it: a variant forked at cts off a shared place stage, asserting its config names the input variant, that its action inputs carry the upstream variant's ODB and no copy under its own results path, and that it builds. All three fail without FLOW_INPUT_VARIANT.

FLOW_VARIANT names the directory a run writes to. It also names the
directory a run reads from, which means a variant that wants to reuse
an upstream variant's results has to physically copy them into its own
directory first. Sharing an expensive front end across experiments —
one synthesis, one floorplan, many routing variants — is a `cp -r` per
fork today.

Split the two. FLOW_INPUT_VARIANT names the variant a run reads from
and gives INPUT_RESULTS_DIR, INPUT_LOG_DIR, INPUT_REPORTS_DIR and
INPUT_OBJECTS_DIR alongside the existing output directories. It
defaults to FLOW_VARIANT, so every INPUT_*_DIR expands to a string
identical to its *_DIR counterpart and an unchanged run is unchanged.

Reads resolve against a search path: RESULTS_DIR first,
INPUT_RESULTS_DIR second. RESULTS_DIR has to come first because a
stage runs several steps in one process — do-place writes
3_1_place_gp_skip_io.odb and the next step reads it back — and a file
this run just wrote must win over the upstream variant's copy of it.
orfs_input_path and orfs_input_glob in util.tcl are the search; every
write still goes straight to RESULTS_DIR.

load_design is the chokepoint: all 18 stage scripts hand it a bare
basename, so routing it through orfs_input_path covers the whole flow.
The remaining reads are the AUTO_MEMORIES globs, find_sdc_file, the
abstract's .spef, yosys_load's netlist, and genMetrics' log/report/
result directories.

find_sdc_file's candidate ordering now compares basenames rather than
full paths. With one directory the two are equivalent, since every
candidate shares a prefix; with two, the directory prefix would
otherwise decide which .sdc wins.

The Makefile's prerequisite graph is deliberately untouched: it still
names $(RESULTS_DIR). A forked variant is driven through the do-
targets, which is what the flow.sh path does anyway.

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>

@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 introduces the FLOW_INPUT_VARIANT variable, allowing stages to read inputs from a different variant directory than the one they write to, which facilitates sharing upstream results without copying directories. The changes include documentation updates, new path-resolution helper procedures in util.tcl, and updates across various Tcl scripts and Makefiles to use these helpers. Feedback on the changes suggests clarifying a potentially confusing circular dependency in the documentation's Mermaid diagram and caching the result of orfs_input_path in generate_abstract.tcl to avoid redundant filesystem searches.

Comment on lines +119 to +141
```mermaid
flowchart LR
subgraph base["FLOW_VARIANT=base — shared front end"]
S["1_synth"] --> F["2_floorplan"] --> P["3_place"] --> C["4_cts"]
end

subgraph io["FLOW_INPUT_VARIANT=base, FLOW_VARIANT=io"]
Q["quick pin placement"] --> IOTCL["io.tcl"]
end

subgraph main["FLOW_INPUT_VARIANT=base, FLOW_VARIANT=main"]
G["5_grt"] --> R["5_route"] --> FIN["6_final"]
end

subgraph hi["FLOW_INPUT_VARIANT=base, FLOW_VARIANT=high_effort"]
G2["5_grt (higher effort)"] --> R2["5_route"] --> FIN2["6_final"]
end

F -. "reads base results" .-> Q
C -. "reads base results" .-> G
C -. "reads base results" .-> G2
IOTCL -- "IO_CONSTRAINTS" --> F
```

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 Mermaid diagram illustrating the use of FLOW_INPUT_VARIANT for a custom pin layout flow is a bit confusing. The arrow IOTCL -- "IO_CONSTRAINTS" --> F suggests a circular dependency, as the base variant's floorplan (F) seems to depend on an output (IOTCL) from the io variant, which itself depends on F.

The accompanying text says "The main flow then re-runs from floorplan with IO_CONSTRAINTS pointing at it". This implies a new floorplan run in a separate variant (e.g., main_with_io), which would read synthesis from base and io.tcl from io.

To improve clarity, consider adjusting the diagram to better reflect this. For example, you could introduce a new floorplan node in a different variant that takes IOTCL as an input, rather than having the arrow point back to the original F in the base variant.

Comment on lines +16 to +17
if { $design_stage >= 6 && [file exists [orfs_input_path $stem.spef]] } {
log_cmd read_spef [orfs_input_path $stem.spef]

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 function orfs_input_path is called twice for the same file, $stem.spef. To improve readability and avoid a redundant file system search, you could store the result in a variable.

if { $design_stage >= 6 && [file exists [set spef_path [orfs_input_path $stem.spef]]] } {
  log_cmd read_spef $spef_path

@oharboe

oharboe commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator Author

duplicate

@oharboe oharboe closed this Aug 26, 2026
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