Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions xlsynth-driver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,21 @@ optimization, and gatification using either the toolchain or the runtime APIs.
Runs the XLS optimizer on an IR file and prints the optimized IR to **stdout**.
Requires `--top <NAME>` to select the entry point.

### `ir2dslx`: IR to simple DSLX

Emits a simple DSLX function corresponding to an XLS IR function by walking
nodes in topological order and producing let-bound expressions. The output is
printed to **stdout**.

- Positional: `<ir_input_file>` – path to the IR package file
- Optional: `--top <NAME>` – entry point function (defaults to the package `top` or first function)

Example:

```shell
xlsynth-driver ir2dslx my_pkg.ir --top add_u32
```

### `ir2pipeline`: IR to pipelined Verilog

Produces a pipelined SystemVerilog design from an IR file. The generated code
Expand Down
55 changes: 55 additions & 0 deletions xlsynth-driver/src/ir2dslx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: Apache-2.0

use crate::toolchain_config::ToolchainConfig;
use clap::ArgMatches;

pub fn handle_ir2dslx(matches: &ArgMatches, _config: &Option<ToolchainConfig>) {
let ir_path = std::path::Path::new(matches.get_one::<String>("ir_input_file").unwrap());
let top_opt = matches.get_one::<String>("ir_top").map(|s| s.as_str());
let pkg = match xlsynth_g8r::xls_ir::ir_parser::parse_path_to_package(ir_path) {
Ok(p) => p,
Err(e) => {
crate::report_cli_error::report_cli_error_and_exit(
"Failed to parse IR",
Some(&format!("{}", e)),
vec![("ir_input_file", &ir_path.display().to_string())],
);
unreachable!();
}
};
let func = if let Some(top) = top_opt {
pkg.get_fn(top).unwrap_or_else(|| {
crate::report_cli_error::report_cli_error_and_exit(
"Top function not found in package",
None,
vec![
("top", top),
("ir_input_file", &ir_path.display().to_string()),
],
);
unreachable!()
})
} else {
pkg.get_top().unwrap_or_else(|| {
crate::report_cli_error::report_cli_error_and_exit(
"No function found in package",
None,
vec![("ir_input_file", &ir_path.display().to_string())],
);
unreachable!()
})
};

match xlsynth_g8r::xls_ir::ir2dslx::emit_fn_as_dslx(func) {
Ok(text) => {
println!("{}", text);
}
Err(e) => {
crate::report_cli_error::report_cli_error_and_exit(
"IR→DSLX emission failed",
Some(&e),
vec![("ir_input_file", &ir_path.display().to_string())],
);
}
}
}
14 changes: 14 additions & 0 deletions xlsynth-driver/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ mod gv2ir;
mod gv_read_stats;
mod ir2combo;
mod ir2delayinfo;
mod ir2dslx;
mod ir2gates;
mod ir2opt;
mod ir2pipeline;
Expand Down Expand Up @@ -500,6 +501,17 @@ fn main() {
),
)
// ir2opt subcommand requires a top symbol
.subcommand(
clap::Command::new("ir2dslx")
.about("Emits a simple DSLX function from IR")
.arg(
clap::Arg::new("ir_input_file")
.help("The input IR file")
.required(true)
.index(1),
)
.add_ir_top_arg(false),
)
.subcommand(
clap::Command::new("ir2opt")
.about("Converts IR to optimized IR")
Expand Down Expand Up @@ -1328,6 +1340,8 @@ fn main() {
ir2opt::handle_ir2opt(matches, &config);
} else if let Some(matches) = matches.subcommand_matches("ir2pipeline") {
ir2pipeline::handle_ir2pipeline(matches, &config);
} else if let Some(matches) = matches.subcommand_matches("ir2dslx") {
ir2dslx::handle_ir2dslx(matches, &config);
} else if let Some(matches) = matches.subcommand_matches("dslx2sv-types") {
dslx2sv_types::handle_dslx2sv_types(matches, &config);
} else if let Some(matches) = matches.subcommand_matches("dslx-show") {
Expand Down
45 changes: 45 additions & 0 deletions xlsynth-driver/tests/invoke_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6260,6 +6260,51 @@ top fn main(x: bits[8]) -> bits[8] {
);
}

// -----------------------------------------------------------------------------
// ir2dslx
// -----------------------------------------------------------------------------

#[test]
fn test_ir2dslx_simple_plus_one() {
let _ = env_logger::builder().is_test(true).try_init();

let ir_text = r#"package p

top fn plus_one(x: bits[32] id=1) -> bits[32] {
one: bits[32] = literal(value=1, id=2)
ret add.3: bits[32] = add(x, one, id=3)
}
"#;

let tmp = tempfile::tempdir().unwrap();
let ir_path = tmp.path().join("p.ir");
std::fs::write(&ir_path, ir_text).unwrap();

let driver = env!("CARGO_BIN_EXE_xlsynth-driver");
let output = std::process::Command::new(driver)
.arg("ir2dslx")
.arg(ir_path.to_str().unwrap())
.arg("--top")
.arg("plus_one")
.output()
.unwrap();
assert!(
output.status.success(),
"stdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let got = stdout.trim();
let expected = r#"fn plus_one(x: u32) -> u32 {
let one: u32 = u32:1;
let add_3: u32 = x + one;
add_3
}"#
.trim();
assert_eq!(got, expected, "stdout: {}", stdout);
}

// -----------------------------------------------------------------------------
// Uninterpreted function (UF) tests for prove-quickcheck
// -----------------------------------------------------------------------------
Expand Down
Loading
Loading