Skip to content

Descendc: CLI functionality for Descend #32

Open
StoeckOverflow wants to merge 14 commits intomainfrom
descendc
Open

Descendc: CLI functionality for Descend #32
StoeckOverflow wants to merge 14 commits intomainfrom
descendc

Conversation

@StoeckOverflow
Copy link

  • CLI Enhancements:
    • Added subcommands (Emit, Build, Run) via clap
    • Checks for essential tools like nvcc and clang-format
  • Error Handling Improvements:
    • Utilizes anyhow for streamlined error propagation and improved context, making debugging easier
    • Future consideration: Dedicated error types for finer error classification and pattern matching
  • CUDA Code Generation Insights:
    • The generated CUDA code (e.g., in examples/infer) uses unsafe for uninitialized holes, which results in empty assignments in the output. This design choice allows compiling GPU-side functions with static arguments without handling host-side IO.
    • As a result, functions like main are translated to have a void return type (reflecting Descend’s unit type), leading to conventional warnings in C++.
    • Exploration of workarounds (e.g., special-casing the main function translation or integrating with existing host-side languages) to address these issues in future iterations is in the works.

[dependencies.descend_derive]
path = "./descend_derive"

[dependencies.clap]
Copy link
Member

Choose a reason for hiding this comment

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

Could you give a brief overview over what these dependencies are used for, so that we can gauge how important they are?

Copy link
Author

Choose a reason for hiding this comment

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

  • clap: Declarative API for defining and parsing the command-line arguments.
  • which: Used to check for the presence of system executables (nvcc, clang-format).
  • predicates: Facilitates expressive assertions in the cli_test.rs (verifying output contains expected text).
  • assert_cmd: Assists in testing command-line applications and enables CLI integration tests (as used in cli_test.rs).
  • log and env_logger: Provides a consistent logging API and allows for configurable logging output. I used it to switch between general information and debug-level output in the CLI. Simple println-style outputs would work as well.
  • anyhow: Simplifies error handling by performing type erasure for errors. It wraps concrete error types in a trait object, allowing you to propagate errors without having to specify their types explicitly. I used it as a neat way to provide error messages, but it may won't be applicable when we merge PR #31 and does not align with the use of custom error types. I will remove this dependency and change the error handling.

Cargo.toml Outdated
version = "2.0.16"

[workspace]
members = ["descend_derive"] No newline at end of file
Copy link
Member

Choose a reason for hiding this comment

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

we should make sure to always include an empty line at the end of every file:

src/main.rs Outdated
.output()
.with_context(|| "Failed to run nvcc command")?;
if !output.status.success() {
return Err(anyhow::anyhow!(
Copy link
Member

Choose a reason for hiding this comment

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

I think anyhow could be a custom error. When calling compile in l.84 we could simply bubble up the error.
How this should work will probably be more clear after PR #31 has been merged.

Copy link
Author

Choose a reason for hiding this comment

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

I introduced two custom errors called NVCCError and ExecutableError in error.rs and removed the use of anyhow. I also added a std::fmt::Display implementation for ErrorReported. This should allow us to bubble up errors in a more controlled way.

src/lib.rs Outdated
pub mod ty_check;

pub fn compile(file_path: &str) -> Result<String, ErrorReported> {
pub fn compile(file_path: &str, output_path: Option<&str>) -> Result<String, ErrorReported> {
Copy link
Member

Choose a reason for hiding this comment

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

Before compile was the entry into the entire compiler. Now there is additional functionality on top. It now seems odd to me to mix the combination of the compilation stages with file access.

I suggest breaking this up:

Suggested change
pub fn compile(file_path: &str, output_path: Option<&str>) -> Result<String, ErrorReported> {
pub fn compile(source: &SourceCode) -> Result<String, ErrorReported> {
// return the generated code or errors
}

I am ignoring that the error reporting should probably be changed according to PR #31.

This way the implementation is more modular. For now, the CLI could open the file and decide whether to write the output to a file or to the standard output stream.

Copy link
Author

Choose a reason for hiding this comment

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

I refactored my implementation on that point. In the changes I just pushed, the compile function remains unchanged, and all file-handling logic has been moved to main.rs.

Ok(println!(
"{}",
descend::compile("examples/infer/transpose.desc")?
descend::compile("examples/infer/transpose.desc", None)?
Copy link
Member

Choose a reason for hiding this comment

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

By making compile only take the SourceCode we do not have to provide None everywhere.

let mut nvcc_cmd = Command::new("nvcc");
nvcc_cmd
.arg(cuda_file)
.arg("-o")
Copy link
Member

Choose a reason for hiding this comment

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

I think it makes sense to delete this file unless explicitly requested.

env_logger::init();
let cli = Cli::parse();

if cli.debug {
Copy link
Member

Choose a reason for hiding this comment

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

Do the debug and verbose flags currently do anything?

Copy link
Author

Choose a reason for hiding this comment

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

I initially integrated both flags to introduce separate logging levels, but I never properly implemented their use. I will push some changes that introduce different logging behavior via a debug flag. For now, maintaining different levels like verbose and debug is unnecessary.

@StoeckOverflow StoeckOverflow marked this pull request as ready for review April 22, 2025 08:07
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.

2 participants