| 
47 | 47 | #include "p4_constraints/frontend/constraint_kind.h"  | 
48 | 48 | #include "p4_constraints/frontend/parser.h"  | 
49 | 49 | #include "z3++.h"  | 
 | 50 | +#include "z3_api.h"  | 
50 | 51 | 
 
  | 
51 | 52 | namespace p4_constraints {  | 
52 | 53 | namespace {  | 
@@ -833,4 +834,160 @@ absl::StatusOr<z3::expr> GetPrefixLength(const SymbolicKey& symbolic_key) {  | 
833 | 834 |   return GetFieldAccess(symbolic_key, "prefix_length");  | 
834 | 835 | }  | 
835 | 836 | 
 
  | 
 | 837 | +// Substitute variable names in `expr`, replacing variables in `src_env` with  | 
 | 838 | +// ones in `dst_env`. Note that `dst_env` is a subset of `src_env` and may not  | 
 | 839 | +// share the same z3 context.  | 
 | 840 | +absl::StatusOr<z3::expr> TranslateBySymbolicEnvironment(  | 
 | 841 | +    z3::expr expr, const SymbolicEnvironment& src_env,  | 
 | 842 | +    const SymbolicEnvironment& dst_env) {  | 
 | 843 | +  for (const auto& entry : dst_env.symbolic_key_by_name) {  | 
 | 844 | +    const auto& key_name = entry.first;  | 
 | 845 | +    const auto& dst_key = entry.second;  | 
 | 846 | +    auto src_it = src_env.symbolic_key_by_name.find(key_name);  | 
 | 847 | +    if (src_it == src_env.symbolic_key_by_name.end()) {  | 
 | 848 | +      return gutils::InvalidArgumentErrorBuilder()  | 
 | 849 | +             << "Cannot rename nonexistent key '" << key_name  | 
 | 850 | +             << "' specified in destination but not in source.";  | 
 | 851 | +    }  | 
 | 852 | +    const SymbolicKey& src_key = src_it->second;  | 
 | 853 | + | 
 | 854 | +    // Replace `src_env` variables appearing in `expr` with the  | 
 | 855 | +    // corresponding `dst_env` variables.  | 
 | 856 | +    z3::expr_vector from(expr.ctx());  | 
 | 857 | +    z3::expr_vector to(expr.ctx());  | 
 | 858 | +    ASSIGN_OR_RETURN(  | 
 | 859 | +        expr,  | 
 | 860 | +        std::visit(  | 
 | 861 | +            gutils::Overload{  | 
 | 862 | +                [&](const SymbolicExact& src_exact)  | 
 | 863 | +                    -> absl::StatusOr<z3::expr> {  | 
 | 864 | +                  const SymbolicExact& dst_exact =  | 
 | 865 | +                      std::get<SymbolicExact>(dst_key);  | 
 | 866 | +                  z3::expr translated_dst_value = z3::to_expr(  | 
 | 867 | +                      expr.ctx(), Z3_translate(dst_exact.value.ctx(),  | 
 | 868 | +                                               dst_exact.value, expr.ctx()));  | 
 | 869 | +                  if (!eq(src_exact.value.get_sort(),  | 
 | 870 | +                          translated_dst_value.get_sort())) {  | 
 | 871 | +                    return gutils::InternalErrorBuilder(GUTILS_LOC)  | 
 | 872 | +                           << "Mismatched Z3 sorts during symbolic translation "  | 
 | 873 | +                              "for "  | 
 | 874 | +                              "key '"  | 
 | 875 | +                           << key_name << "': src sort is "  | 
 | 876 | +                           << src_exact.value.get_sort() << ", dst sort is "  | 
 | 877 | +                           << translated_dst_value.get_sort();  | 
 | 878 | +                  }  | 
 | 879 | +                  from.push_back(src_exact.value);  | 
 | 880 | +                  to.push_back(translated_dst_value);  | 
 | 881 | +                  return expr.substitute(from, to);  | 
 | 882 | +                },  | 
 | 883 | +                [&](const SymbolicTernary& src_ternary)  | 
 | 884 | +                    -> absl::StatusOr<z3::expr> {  | 
 | 885 | +                  const SymbolicTernary& dst_ternary =  | 
 | 886 | +                      std::get<SymbolicTernary>(dst_key);  | 
 | 887 | +                  // Translate dst_ternary values to the context of expr.  | 
 | 888 | +                  z3::expr translated_dst_value = z3::to_expr(  | 
 | 889 | +                      expr.ctx(), Z3_translate(dst_ternary.value.ctx(),  | 
 | 890 | +                                               dst_ternary.value, expr.ctx()));  | 
 | 891 | +                  z3::expr translated_dst_mask = z3::to_expr(  | 
 | 892 | +                      expr.ctx(), Z3_translate(dst_ternary.mask.ctx(),  | 
 | 893 | +                                               dst_ternary.mask, expr.ctx()));  | 
 | 894 | +                  if (!eq(src_ternary.value.get_sort(),  | 
 | 895 | +                          translated_dst_value.get_sort())) {  | 
 | 896 | +                    return gutils::InternalErrorBuilder(GUTILS_LOC)  | 
 | 897 | +                           << "Mismatched Z3 sorts during symbolic translation "  | 
 | 898 | +                              "for "  | 
 | 899 | +                              "key '"  | 
 | 900 | +                           << key_name << "': src sort is "  | 
 | 901 | +                           << src_ternary.value.get_sort() << ", dst sort is "  | 
 | 902 | +                           << translated_dst_value.get_sort();  | 
 | 903 | +                  }  | 
 | 904 | +                  if (!eq(src_ternary.mask.get_sort(),  | 
 | 905 | +                          translated_dst_mask.get_sort())) {  | 
 | 906 | +                    return gutils::InternalErrorBuilder(GUTILS_LOC)  | 
 | 907 | +                           << "Mismatched Z3 sorts during symbolic translation "  | 
 | 908 | +                              "for "  | 
 | 909 | +                              "mask of key '"  | 
 | 910 | +                           << key_name << "': src sort is "  | 
 | 911 | +                           << src_ternary.mask.get_sort() << ", dst sort is "  | 
 | 912 | +                           << translated_dst_mask.get_sort();  | 
 | 913 | +                  }  | 
 | 914 | +                  from.push_back(src_ternary.value);  | 
 | 915 | +                  to.push_back(translated_dst_value);  | 
 | 916 | +                  from.push_back(src_ternary.mask);  | 
 | 917 | +                  to.push_back(translated_dst_mask);  | 
 | 918 | +                  return expr.substitute(from, to);  | 
 | 919 | +                },  | 
 | 920 | +                [&](const SymbolicLpm& src_lpm) -> absl::StatusOr<z3::expr> {  | 
 | 921 | +                  const SymbolicLpm& dst_lpm = std::get<SymbolicLpm>(dst_key);  | 
 | 922 | +                  z3::expr translated_dst_value = z3::to_expr(  | 
 | 923 | +                      expr.ctx(), Z3_translate(dst_lpm.value.ctx(),  | 
 | 924 | +                                               dst_lpm.value, expr.ctx()));  | 
 | 925 | +                  z3::expr translated_dst_prefix_length = z3::to_expr(  | 
 | 926 | +                      expr.ctx(),  | 
 | 927 | +                      Z3_translate(dst_lpm.prefix_length.ctx(),  | 
 | 928 | +                                   dst_lpm.prefix_length, expr.ctx()));  | 
 | 929 | +                  if (!eq(src_lpm.value.get_sort(),  | 
 | 930 | +                          translated_dst_value.get_sort())) {  | 
 | 931 | +                    return gutils::InternalErrorBuilder(GUTILS_LOC)  | 
 | 932 | +                           << "Mismatched Z3 sorts during symbolic translation "  | 
 | 933 | +                              "for "  | 
 | 934 | +                              "key '"  | 
 | 935 | +                           << key_name << "': src sort is "  | 
 | 936 | +                           << src_lpm.value.get_sort() << ", dst sort is "  | 
 | 937 | +                           << translated_dst_value.get_sort();  | 
 | 938 | +                  }  | 
 | 939 | +                  if (!eq(src_lpm.prefix_length.get_sort(),  | 
 | 940 | +                          translated_dst_prefix_length.get_sort())) {  | 
 | 941 | +                    return gutils::InternalErrorBuilder(GUTILS_LOC)  | 
 | 942 | +                           << "Mismatched Z3 sorts during symbolic translation "  | 
 | 943 | +                              "for "  | 
 | 944 | +                              "prefix_length of key '"  | 
 | 945 | +                           << key_name << "': src sort is "  | 
 | 946 | +                           << src_lpm.prefix_length.get_sort()  | 
 | 947 | +                           << ", dst sort is "  | 
 | 948 | +                           << translated_dst_prefix_length.get_sort();  | 
 | 949 | +                  }  | 
 | 950 | +                  from.push_back(src_lpm.value);  | 
 | 951 | +                  to.push_back(translated_dst_value);  | 
 | 952 | +                  from.push_back(src_lpm.prefix_length);  | 
 | 953 | +                  to.push_back(translated_dst_prefix_length);  | 
 | 954 | +                  return expr.substitute(from, to);  | 
 | 955 | +                },  | 
 | 956 | +            },  | 
 | 957 | +            src_key));  | 
 | 958 | +  }  | 
 | 959 | + | 
 | 960 | +  // Substitute attribute names.  | 
 | 961 | +  for (const auto& [attribute_name, dst_attribute] :  | 
 | 962 | +       dst_env.symbolic_attribute_by_name) {  | 
 | 963 | +    auto src_it = src_env.symbolic_attribute_by_name.find(attribute_name);  | 
 | 964 | +    if (src_it == src_env.symbolic_attribute_by_name.end()) continue;  | 
 | 965 | +    const SymbolicAttribute& src_attribute = src_it->second;  | 
 | 966 | +    z3::expr translated_dst_value =  | 
 | 967 | +        z3::to_expr(expr.ctx(), Z3_translate(dst_attribute.value.ctx(),  | 
 | 968 | +                                             dst_attribute.value, expr.ctx()));  | 
 | 969 | +    z3::expr_vector from(expr.ctx());  | 
 | 970 | +    z3::expr_vector to(expr.ctx());  | 
 | 971 | +    from.push_back(src_attribute.value);  | 
 | 972 | +    to.push_back(translated_dst_value);  | 
 | 973 | +    expr = expr.substitute(from, to);  | 
 | 974 | +  }  | 
 | 975 | +  return expr;  | 
 | 976 | +}  | 
 | 977 | + | 
 | 978 | +absl::Status ConstraintSolver::ExportConstraintsToTargetSolver(  | 
 | 979 | +    z3::solver& solver, const SymbolicEnvironment& environment) {  | 
 | 980 | +  z3::expr_vector constraints(solver.ctx());  | 
 | 981 | +  for (z3::expr assertion : solver_->assertions()) {  | 
 | 982 | +    ASSIGN_OR_RETURN(  | 
 | 983 | +        z3::expr translated_assertion,  | 
 | 984 | +        TranslateBySymbolicEnvironment(assertion, environment_, environment));  | 
 | 985 | +    constraints.push_back(z3::to_expr(  | 
 | 986 | +        solver.ctx(),  | 
 | 987 | +        Z3_translate(*context_, translated_assertion, solver.ctx())));  | 
 | 988 | +  }  | 
 | 989 | +  solver.add(constraints);  | 
 | 990 | +  return absl::OkStatus();  | 
 | 991 | +}  | 
 | 992 | + | 
836 | 993 | }  // namespace p4_constraints  | 
0 commit comments