|
14 | 14 |
|
15 | 15 | #include "xls/dslx/cpp_transpiler/cpp_emitter.h" |
16 | 16 |
|
| 17 | +#include <algorithm> |
17 | 18 | #include <cstdint> |
18 | 19 | #include <functional> |
| 20 | +#include <iterator> |
19 | 21 | #include <memory> |
20 | 22 | #include <optional> |
21 | 23 | #include <string> |
|
24 | 26 | #include <variant> |
25 | 27 | #include <vector> |
26 | 28 |
|
| 29 | +#include "absl/algorithm/container.h" |
27 | 30 | #include "absl/base/no_destructor.h" |
28 | 31 | #include "absl/container/flat_hash_map.h" |
29 | 32 | #include "absl/container/flat_hash_set.h" |
30 | 33 | #include "absl/status/status.h" |
31 | 34 | #include "absl/status/statusor.h" |
| 35 | +#include "absl/strings/match.h" |
32 | 36 | #include "absl/strings/str_cat.h" |
33 | 37 | #include "absl/strings/str_format.h" |
34 | 38 | #include "absl/strings/str_join.h" |
| 39 | +#include "absl/types/span.h" |
35 | 40 | #include "xls/common/case_converters.h" |
36 | 41 | #include "xls/common/indent.h" |
37 | 42 | #include "xls/common/status/ret_check.h" |
@@ -418,6 +423,10 @@ class TypeRefCppEmitter : public CppEmitter { |
418 | 423 | // std::array. |
419 | 424 | class ArrayCppEmitter : public CppEmitter { |
420 | 425 | public: |
| 426 | + // NOTE: until we implement variable name tracking across generated scopes, |
| 427 | + // prefixes must be kept unique across all emitters and generators |
| 428 | + std::string kArrayVarPrefix = "elements"; |
| 429 | + |
421 | 430 | explicit ArrayCppEmitter(const CppType& cpp_type, std::string_view dslx_type, |
422 | 431 | int64_t array_size, |
423 | 432 | std::unique_ptr<CppEmitter> element_emitter) |
@@ -455,23 +464,27 @@ class ArrayCppEmitter : public CppEmitter { |
455 | 464 |
|
456 | 465 | std::string AssignToValue(std::string_view lhs, std::string_view rhs, |
457 | 466 | int64_t nesting) const override { |
| 467 | + std::string tmp_var_name = |
| 468 | + UniqueVarName({std::string(rhs)}, kArrayVarPrefix); |
458 | 469 | std::string ind_var = absl::StrCat("i", nesting); |
459 | 470 |
|
460 | 471 | std::vector<std::string> loop_body; |
461 | 472 | loop_body.push_back("::xls::Value element;"); |
462 | 473 | std::string element_assignment = element_emitter_->AssignToValue( |
463 | 474 | "element", absl::StrFormat("%s[%s]", rhs, ind_var), nesting + 1); |
464 | 475 | loop_body.push_back(element_assignment); |
465 | | - loop_body.push_back("elements.push_back(element);"); |
| 476 | + loop_body.push_back( |
| 477 | + absl::StrFormat("%s.push_back(element);", tmp_var_name)); |
466 | 478 |
|
467 | 479 | std::vector<std::string> pieces; |
468 | | - pieces.push_back("std::vector<::xls::Value> elements;"); |
| 480 | + pieces.push_back( |
| 481 | + absl::StrFormat("std::vector<::xls::Value> %s;", tmp_var_name)); |
469 | 482 | pieces.push_back(absl::StrFormat("for (int64_t %s = 0; %s < %d; ++%s) {", |
470 | 483 | ind_var, ind_var, array_size(), ind_var)); |
471 | 484 | pieces.push_back(Indent(absl::StrJoin(loop_body, "\n"), 2)); |
472 | 485 | pieces.push_back("}"); |
473 | | - pieces.push_back( |
474 | | - absl::StrFormat("%s = ::xls::Value::ArrayOrDie(elements);", lhs)); |
| 486 | + pieces.push_back(absl::StrFormat("%s = ::xls::Value::ArrayOrDie(%s);", lhs, |
| 487 | + tmp_var_name)); |
475 | 488 | std::string lines = absl::StrJoin(pieces, "\n"); |
476 | 489 |
|
477 | 490 | return absl::StrCat("{\n", Indent(lines, 2), "\n}"); |
@@ -575,6 +588,10 @@ class ArrayCppEmitter : public CppEmitter { |
575 | 588 | // std::tuple. |
576 | 589 | class TupleCppEmitter : public CppEmitter { |
577 | 590 | public: |
| 591 | + // NOTE: until we implement variable name tracking across generated scopes, |
| 592 | + // prefixes must be kept unique across all emitters and generators |
| 593 | + std::string kTupleVarPrefix = "entries"; |
| 594 | + |
578 | 595 | explicit TupleCppEmitter( |
579 | 596 | const CppType& cpp_type, std::string_view dslx_type, |
580 | 597 | std::vector<std::unique_ptr<CppEmitter>> element_emitters) |
@@ -606,16 +623,20 @@ class TupleCppEmitter : public CppEmitter { |
606 | 623 | std::string AssignToValue(std::string_view lhs, std::string_view rhs, |
607 | 624 | int64_t nesting) const override { |
608 | 625 | std::vector<std::string> pieces; |
609 | | - pieces.push_back("std::vector<::xls::Value> members;"); |
610 | | - pieces.push_back(absl::StrFormat("members.resize(%d);", size())); |
| 626 | + std::vector<std::string> user_defined_names{std::string(rhs)}; |
| 627 | + std::string tmp_var_name = |
| 628 | + UniqueVarName(user_defined_names, kTupleVarPrefix); |
| 629 | + pieces.push_back( |
| 630 | + absl::StrFormat("std::vector<::xls::Value> %s;", tmp_var_name)); |
| 631 | + pieces.push_back(absl::StrFormat("%s.resize(%d);", tmp_var_name, size())); |
611 | 632 | for (int64_t i = 0; i < size(); ++i) { |
612 | 633 | std::string assignment = element_emitters_[i]->AssignToValue( |
613 | | - absl::StrFormat("members[%d]", i), |
| 634 | + absl::StrFormat("%s[%d]", tmp_var_name, i), |
614 | 635 | absl::StrFormat("std::get<%d>(%s)", i, rhs), nesting + 1); |
615 | 636 | pieces.push_back(assignment); |
616 | 637 | } |
617 | 638 | pieces.push_back( |
618 | | - absl::StrFormat("%s = ::xls::Value::Tuple(members);", lhs)); |
| 639 | + absl::StrFormat("%s = ::xls::Value::Tuple(%s);", lhs, tmp_var_name)); |
619 | 640 | return absl::StrFormat("{\n%s\n}", Indent(absl::StrJoin(pieces, "\n"), 2)); |
620 | 641 | } |
621 | 642 |
|
@@ -803,8 +824,29 @@ std::string SanitizeCppName(std::string_view name) { |
803 | 824 | return std::string{name}; |
804 | 825 | } |
805 | 826 |
|
| 827 | +std::string PreserveTrimmedCharacter(std::string_view original, |
| 828 | + std::string_view sanitized, |
| 829 | + char c_to_preserve) { |
| 830 | + bool all_match_so_far = true; |
| 831 | + auto still_underscore = [&](char c) -> bool { |
| 832 | + all_match_so_far &= (c == c_to_preserve); |
| 833 | + return all_match_so_far; |
| 834 | + }; |
| 835 | + int64_t leading_underscores = |
| 836 | + std::count_if(original.begin(), original.end(), still_underscore); |
| 837 | + all_match_so_far = true; |
| 838 | + int64_t trailing_underscores = |
| 839 | + std::count_if(original.rbegin(), original.rend(), still_underscore); |
| 840 | + return absl::StrCat(std::string(leading_underscores, c_to_preserve), |
| 841 | + sanitized, |
| 842 | + std::string(trailing_underscores, c_to_preserve)); |
| 843 | +} |
| 844 | + |
806 | 845 | std::string DslxTypeNameToCpp(std::string_view dslx_type) { |
807 | | - return SanitizeCppName(Camelize(dslx_type)); |
| 846 | + std::string cpp_name = SanitizeCppName(Camelize(dslx_type)); |
| 847 | + // Retain trimmed underscores to ensure names are unique. This matters for |
| 848 | + // user defined names only differing by underscores. |
| 849 | + return PreserveTrimmedCharacter(dslx_type, cpp_name, '_'); |
808 | 850 | } |
809 | 851 |
|
810 | 852 | std::string DslxModuleNameToCppNamespace(std::string_view dslx_module) { |
@@ -856,4 +898,27 @@ std::string DslxModuleNameToCppNamespace(std::string_view dslx_module) { |
856 | 898 | "Unsupported TypeAnnotation kind: ", type_annotation->ToString())); |
857 | 899 | } |
858 | 900 |
|
| 901 | +std::string UniqueVarName(absl::Span<const std::string> user_names, |
| 902 | + std::string_view prefix) { |
| 903 | + std::string unique_name = std::string(prefix); |
| 904 | + if (!absl::c_contains(user_names, unique_name)) { |
| 905 | + return unique_name; |
| 906 | + } |
| 907 | + std::vector<std::string> existing_user_names; |
| 908 | + absl::c_copy_if(user_names, std::back_inserter(existing_user_names), |
| 909 | + [prefix](std::string_view name) { |
| 910 | + return absl::StartsWith(name, prefix); |
| 911 | + }); |
| 912 | + absl::c_sort(existing_user_names); |
| 913 | + // Appending a character avoids collision with previous names because the |
| 914 | + // potentially colliding names are sorted. Names [x, x_, x__, ...] will be |
| 915 | + // caught by subsequent iterations and enough "_" will be appended. |
| 916 | + for (int64_t i = 0; i < existing_user_names.size(); ++i) { |
| 917 | + if (existing_user_names[i] == unique_name) { |
| 918 | + unique_name += "_"; |
| 919 | + } |
| 920 | + } |
| 921 | + return unique_name; |
| 922 | +} |
| 923 | + |
859 | 924 | } // namespace xls::dslx |
0 commit comments