Skip to content

Commit

Permalink
Merge pull request #1443 from xlsynth:cdleary/2024-05-30-xls-value-c-api
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 639919532
  • Loading branch information
copybara-github committed Jun 3, 2024
2 parents 2d2eb14 + 64fa2ad commit 5f8de03
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 2 deletions.
2 changes: 2 additions & 0 deletions xls/public/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ cc_library(
hdrs = ["c_api.h"],
deps = [
":runtime_build_actions",
"//xls/interpreter:ir_interpreter",
"//xls/ir:ir_parser",
],
)

Expand Down
126 changes: 126 additions & 0 deletions xls/public/c_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "xls/public/c_api.h"

#include "xls/interpreter/function_interpreter.h"
#include "xls/ir/ir_parser.h"
#include "xls/public/runtime_build_actions.h"

namespace {
Expand Down Expand Up @@ -45,6 +47,7 @@ bool xls_convert_dslx_to_ir(const char* dslx, const char* path,
CHECK(dslx != nullptr);
CHECK(path != nullptr);
CHECK(dslx_stdlib_path != nullptr);
CHECK(error_out != nullptr);

std::vector<std::filesystem::path> additional_search_paths_cpp =
ToCpp(additional_search_paths, additional_search_paths_count);
Expand All @@ -67,6 +70,7 @@ bool xls_convert_dslx_path_to_ir(const char* path, const char* dslx_stdlib_path,
char** error_out, char** ir_out) {
CHECK(path != nullptr);
CHECK(dslx_stdlib_path != nullptr);
CHECK(error_out != nullptr);

std::vector<std::filesystem::path> additional_search_paths_cpp =
ToCpp(additional_search_paths, additional_search_paths_count);
Expand All @@ -83,4 +87,126 @@ bool xls_convert_dslx_path_to_ir(const char* path, const char* dslx_stdlib_path,
return false;
}

bool xls_parse_typed_value(const char* input, char** error_out,
xls_value** xls_value_out) {
CHECK(input != nullptr);
CHECK(error_out != nullptr);
CHECK(xls_value_out != nullptr);

absl::StatusOr<xls::Value> value_or = xls::Parser::ParseTypedValue(input);
if (value_or.ok()) {
*xls_value_out = reinterpret_cast<xls_value*>(
new xls::Value(std::move(value_or).value()));
return true;
}

*xls_value_out = nullptr;
*error_out = ToOwnedCString(value_or.status().ToString());
return false;
}

void xls_value_free(xls_value* v) {
if (v == nullptr) {
return;
}
delete reinterpret_cast<xls::Value*>(v);
}

void xls_package_free(struct xls_package* p) {
if (p == nullptr) {
return;
}
delete reinterpret_cast<xls::Package*>(p);
}

bool xls_value_to_string(const struct xls_value* v, char** string_out) {
CHECK(v != nullptr);
CHECK(string_out != nullptr);
std::string s = reinterpret_cast<const xls::Value*>(v)->ToString();
*string_out = strdup(s.c_str());
return *string_out != nullptr;
}

bool xls_value_eq(const struct xls_value* v, const struct xls_value* w) {
CHECK(v != nullptr);
CHECK(w != nullptr);

const auto* lhs = reinterpret_cast<const xls::Value*>(v);
const auto* rhs = reinterpret_cast<const xls::Value*>(w);
return *lhs == *rhs;
}

bool xls_parse_ir_package(const char* ir, const char* filename,
char** error_out,
struct xls_package** xls_package_out) {
CHECK(ir != nullptr);
CHECK(error_out != nullptr);
CHECK(xls_package_out != nullptr);

std::optional<std::string_view> cpp_filename;
if (filename != nullptr) {
cpp_filename.emplace(filename);
}
absl::StatusOr<std::unique_ptr<xls::Package>> package_or =
xls::Parser::ParsePackage(ir, cpp_filename);
if (package_or.ok()) {
*xls_package_out =
reinterpret_cast<xls_package*>(package_or.value().release());
*error_out = nullptr;
return true;
}

*xls_package_out = nullptr;
*error_out = ToOwnedCString(package_or.status().ToString());
return false;
}

bool xls_package_get_function(struct xls_package* package,
const char* function_name, char** error_out,
struct xls_function** result_out) {
xls::Package* xls_package = reinterpret_cast<xls::Package*>(package);
absl::StatusOr<xls::Function*> function_or =
xls_package->GetFunction(function_name);
if (function_or.ok()) {
*result_out = reinterpret_cast<struct xls_function*>(function_or.value());
return true;
}

*result_out = nullptr;
*error_out = ToOwnedCString(function_or.status().ToString());
return false;
}

bool xls_interpret_function(struct xls_function* function, size_t argc,
const struct xls_value** args, char** error_out,
struct xls_value** result_out) {
CHECK(function != nullptr);
CHECK(args != nullptr);

xls::Function* xls_function = reinterpret_cast<xls::Function*>(function);

std::vector<xls::Value> xls_args;
xls_args.reserve(argc);
for (size_t i = 0; i < argc; ++i) {
CHECK(args[i] != nullptr);
xls_args.push_back(*reinterpret_cast<const xls::Value*>(args[i]));
}

absl::StatusOr<xls::InterpreterResult<xls::Value>> result_or =
xls::InterpretFunction(xls_function, xls_args);
if (result_or.ok()) {
// TODO(cdleary): 2024-05-30 We should pass back interpreter events through
// this API instead of dropping them.
xls::Value result_value =
xls::DropInterpreterEvents(std::move(result_or)).value();
*result_out = reinterpret_cast<struct xls_value*>(
new xls::Value(std::move(result_value)));
return true;
}

*result_out = nullptr;
*error_out = ToOwnedCString(result_or.status().ToString());
return false;
}

} // extern "C"
42 changes: 42 additions & 0 deletions xls/public/c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@

extern "C" {

// Opaque structs.
struct xls_value;
struct xls_package;
struct xls_function;

bool xls_convert_dslx_to_ir(const char* dslx, const char* path,
const char* module_name,
const char* dslx_stdlib_path,
Expand All @@ -49,6 +54,43 @@ bool xls_convert_dslx_path_to_ir(const char* path, const char* dslx_stdlib_path,
size_t additional_search_paths_count,
char** error_out, char** ir_out);

// Parses a string that represents a typed XLS value; e.g. `bits[32]:0x42`.
bool xls_parse_typed_value(const char* input, char** error_out,
struct xls_value** xls_value_out);

// Returns a string representation of the given value `v`.
bool xls_value_to_string(const struct xls_value* v, char** string_out);

// Returns whether `v` is equal to `w`.
bool xls_value_eq(const struct xls_value* v, const struct xls_value* w);

// Deallocates a value, e.g. one as created by `xls_parse_typed_value`.
void xls_value_free(struct xls_value* v);

void xls_package_free(struct xls_package* p);

// Parses IR text to a package.

// Note: `filename` may be nullptr.
bool xls_parse_ir_package(const char* ir, const char* filename,
char** error_out,
struct xls_package** xls_package_out);

// Returns a function contained within the given `package`.
//
// Note: the returned function does not need to be freed, it is tied to the
// package's lifetime.
bool xls_package_get_function(struct xls_package* package,
const char* function_name, char** error_out,
struct xls_function** result_out);

// Interprets the given `function` using the given `args` (an array of size
// `argc`) -- interpretation runs to a function result placed in `result_out`,
// or `error_out` is populated and false is returned in the event of an error.
bool xls_interpret_function(struct xls_function* function, size_t argc,
const struct xls_value** args, char** error_out,
struct xls_value** result_out);

} // extern "C"

#endif // XLS_PUBLIC_C_API_H_
49 changes: 47 additions & 2 deletions xls/public/c_api_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace {

using testing::HasSubstr;

// Smoke test for ConvertDslxToIr C API.
// Smoke test for `xls_convert_dslx_to_ir` C API.
TEST(XlsCApiTest, ConvertDslxToIrSimple) {
const std::string kProgram = "fn id(x: u32) -> u32 { x }";
const char* additional_search_paths[] = {};
Expand Down Expand Up @@ -75,7 +75,7 @@ TEST(XlsCApiTest, ConvertDslxToIrError) {
EXPECT_THAT(error_out, HasSubstr("Unrecognized character: '@'"));
}

// Smoke test for ConvertDslxPathToIr C API.
// Smoke test for `xls_convert_dslx_path_to_ir` C API.
TEST(XlsCApiTest, ConvertDslxPathToIr) {
const std::string kProgram = "fn id(x: u32) -> u32 { x }";

Expand Down Expand Up @@ -104,4 +104,49 @@ TEST(XlsCApiTest, ConvertDslxPathToIr) {
EXPECT_THAT(ir_out, HasSubstr("fn __my_module__id"));
}

TEST(XlsCApiTest, ParseTypedValueAndFreeIt) {
char* error = nullptr;
struct xls_value* value = nullptr;
ASSERT_TRUE(xls_parse_typed_value("bits[32]:0x42", &error, &value));

char* string_out = nullptr;
ASSERT_TRUE(xls_value_to_string(value, &string_out));
EXPECT_EQ(std::string{string_out}, "bits[32]:66");
free(string_out);

xls_value_free(value);
}

TEST(XlsCApiTest, ParsePackageAndInterpretFunctionInIt) {
const std::string kPackage = R"(
package p
fn f(x: bits[32]) -> bits[32] {
ret y: bits[32] = identity(x)
}
)";

char* error = nullptr;
struct xls_package* package = nullptr;
ASSERT_TRUE(xls_parse_ir_package(kPackage.c_str(), "p.ir", &error, &package))
<< "xls_parse_ir_package error: " << error;
absl::Cleanup free_package([package] { xls_package_free(package); });

struct xls_function* function = nullptr;
ASSERT_TRUE(xls_package_get_function(package, "f", &error, &function));

struct xls_value* ft = nullptr;
ASSERT_TRUE(xls_parse_typed_value("bits[32]:0x42", &error, &ft));
absl::Cleanup free_ft([ft] { xls_value_free(ft); });

const struct xls_value* args[] = {ft};

struct xls_value* result = nullptr;
ASSERT_TRUE(
xls_interpret_function(function, /*argc=*/1, args, &error, &result));
absl::Cleanup free_result([result] { xls_value_free(result); });

ASSERT_TRUE(xls_value_eq(ft, result));
}

} // namespace

0 comments on commit 5f8de03

Please sign in to comment.