From c67200ef72e42b2b3b9f72f46674ac433fabf8bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Feb 2024 08:28:18 -0800 Subject: [PATCH 01/69] update versions Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 4 ++-- scripts/release.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39f89ae74..ba3ec7bce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.12.6.0 LANGUAGES CXX) +project(Z3 VERSION 4.13.0.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 7cc5a0933..d91feea9f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 12, 6, 0) # express a default build version or pick up ci build version + set_version(4, 13, 0, 0) # express a default build version or pick up ci build version # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index f6c3c66c7..4b9698c14 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,7 +1,7 @@ variables: Major: '4' - Minor: '12' - Patch: '6' + Minor: '13' + Patch: '0' ReleaseVersion: $(Major).$(Minor).$(Patch) AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) NightlyVersion: $(AssemblyVersion)-$(Build.buildId) diff --git a/scripts/release.yml b/scripts/release.yml index 7a2c4ef41..083e58aee 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.12.6' + ReleaseVersion: '4.13.0' stages: From 2880ea39719971226e616d1077788288d6107632 Mon Sep 17 00:00:00 2001 From: John Fleisher Date: Mon, 26 Feb 2024 12:06:28 -0500 Subject: [PATCH 02/69] convert formatting tabs to spaces (#7140) * Update nightly.yaml for Azure Pipelines match nightly builds to release builds * Fix nightly.yaml * fix indent * fix indent * convert tabs to spaces for proper formatting in yaml --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4b9698c14..da95812d2 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -247,7 +247,7 @@ stages: displayName: 'Download macOS Arm64 Build' inputs: artifact: 'MacArm64' - path: $(Agent.TempDirectory)\package + path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: versionSpec: 5.x From 91886dafcae4d6b2717ae751af38422a2e8d7077 Mon Sep 17 00:00:00 2001 From: zapashcanon Date: Thu, 29 Feb 2024 17:54:53 +0100 Subject: [PATCH 03/69] some code cleaning and complexity improvements (#7133) * do not use `and` for non mutually recursive types * use List.init, fix complexity of a few operations and make some code more readable * explicit some parameters to make working without LSP/Merlin easier * use fold_left instead of filteri because it is not available on old OCaml versions --- src/api/ml/z3.ml | 192 ++++++++++++++++++------------------- src/api/ml/z3native.ml.pre | 60 ++++++------ 2 files changed, 126 insertions(+), 126 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 166e474d9..0be6e57a0 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -8,7 +8,7 @@ open Z3enums exception Error of string -let _ = Callback.register_exception "Z3EXCEPTION" (Error "") +let () = Callback.register_exception "Z3EXCEPTION" (Error "") type context = Z3native.context @@ -27,22 +27,9 @@ struct let full_version : string = Z3native.get_full_version() - let to_string = - string_of_int major ^ "." ^ - string_of_int minor ^ "." ^ - string_of_int build ^ "." ^ - string_of_int revision + let to_string = Printf.sprintf "%d.%d.%d.%d" major minor build revision end -let mk_list f n = - let rec mk_list' i accu = - if i >= n then - List.rev accu - else - mk_list' (i + 1) ((f i)::accu) - in - mk_list' 0 [] - let check_int32 v = v = Int32.to_int (Int32.of_int v) let mk_int_expr ctx v ty = @@ -68,7 +55,7 @@ let interrupt (ctx:context) = module Symbol = struct type symbol = Z3native.symbol - let gc = Z3native.context_of_symbol + let gc s = Z3native.context_of_symbol s let kind o = symbol_kind_of_int (Z3native.get_symbol_kind (gc o) o) let is_int_symbol o = kind o = INT_SYMBOL @@ -80,8 +67,8 @@ struct | INT_SYMBOL -> string_of_int (Z3native.get_symbol_int (gc o) o) | STRING_SYMBOL -> Z3native.get_symbol_string (gc o) o - let mk_int = Z3native.mk_int_symbol - let mk_string = Z3native.mk_string_symbol + let mk_int ctx = Z3native.mk_int_symbol ctx + let mk_string ctx s = Z3native.mk_string_symbol ctx s let mk_ints ctx names = List.map (mk_int ctx) names let mk_strings ctx names = List.map (mk_string ctx) names @@ -135,12 +122,12 @@ sig val translate : ast -> context -> ast end = struct type ast = Z3native.ast - let gc = Z3native.context_of_ast + let gc a = Z3native.context_of_ast a module ASTVector = struct type ast_vector = Z3native.ast_vector - let gc = Z3native.context_of_ast_vector + let gc v = Z3native.context_of_ast_vector v let mk_ast_vector = Z3native.mk_ast_vector let get_size (x:ast_vector) = Z3native.ast_vector_size (gc x) x @@ -153,12 +140,12 @@ end = struct let to_list (x:ast_vector) = let xs = get_size x in let f i = get x i in - mk_list f xs + List.init xs f let to_expr_list (x:ast_vector) = let xs = get_size x in let f i = get x i in - mk_list f xs + List.init xs f let to_string x = Z3native.ast_vector_to_string (gc x) x end @@ -166,7 +153,7 @@ end = struct module ASTMap = struct type ast_map = Z3native.ast_map - let gc = Z3native.context_of_ast_map + let gc m = Z3native.context_of_ast_map m let mk_ast_map = Z3native.mk_ast_map let contains (x:ast_map) (key:ast) = Z3native.ast_map_contains (gc x) x key @@ -231,7 +218,7 @@ sig val mk_uninterpreted_s : context -> string -> sort end = struct type sort = Z3native.sort - let gc = Z3native.context_of_ast + let gc a = Z3native.context_of_ast a let equal a b = (a = b) || (gc a = gc b && Z3native.is_eq_sort (gc a) a b) @@ -239,7 +226,7 @@ end = struct let get_sort_kind (x:sort) = sort_kind_of_int (Z3native.get_sort_kind (gc x) x) let get_name (x:sort) = Z3native.get_sort_name (gc x) x let to_string (x:sort) = Z3native.sort_to_string (gc x) x - let mk_uninterpreted = Z3native.mk_uninterpreted_sort + let mk_uninterpreted ctx s = Z3native.mk_uninterpreted_sort ctx s let mk_uninterpreted_s (ctx:context) (s:string) = mk_uninterpreted ctx (Symbol.mk_string ctx s) end @@ -290,7 +277,7 @@ sig val apply : func_decl -> Expr.expr list -> Expr.expr end = struct type func_decl = AST.ast - let gc = Z3native.context_of_ast + let gc a = Z3native.context_of_ast a module Parameter = struct @@ -378,7 +365,7 @@ end = struct let get_domain (x:func_decl) = let n = get_domain_size x in let f i = Z3native.get_domain (gc x) x i in - mk_list f n + List.init n f let get_range (x:func_decl) = Z3native.get_range (gc x) x let get_decl_kind (x:func_decl) = decl_kind_of_int (Z3native.get_decl_kind (gc x) x) @@ -397,7 +384,7 @@ end = struct | PARAMETER_FUNC_DECL -> Parameter.P_Fdl (Z3native.get_decl_func_decl_parameter (gc x) x i) | PARAMETER_RATIONAL -> Parameter.P_Rat (Z3native.get_decl_rational_parameter (gc x) x i) in - mk_list f n + List.init n f let apply (x:func_decl) (args:Expr.expr list) = Expr.expr_of_func_app (gc x) x args end @@ -426,12 +413,12 @@ sig val set_print_mode : context -> Z3enums.ast_print_mode -> unit end = struct type params = Z3native.params - let gc = Z3native.context_of_params + let gc p = Z3native.context_of_params p module ParamDescrs = struct type param_descrs = Z3native.param_descrs - let gc = Z3native.context_of_param_descrs + let gc p = Z3native.context_of_param_descrs p let validate (x:param_descrs) (p:params) = Z3native.params_validate (gc x) p x let get_kind (x:param_descrs) (name:Symbol.symbol) = param_kind_of_int (Z3native.param_descrs_get_kind (gc x) x name) @@ -439,7 +426,7 @@ end = struct let get_names (x:param_descrs) = let n = Z3native.param_descrs_size (gc x) x in let f i = Z3native.param_descrs_get_name (gc x) x i in - mk_list f n + List.init n f let get_size (x:param_descrs) = Z3native.param_descrs_size (gc x) x let to_string (x:param_descrs) = Z3native.param_descrs_to_string (gc x) x @@ -491,7 +478,7 @@ sig val compare : expr -> expr -> int end = struct type expr = AST.ast - let gc = Z3native.context_of_ast + let gc a = Z3native.context_of_ast a let expr_of_ast a = let q = Z3enums.ast_kind_of_int (Z3native.get_ast_kind (gc a) a) in @@ -517,7 +504,7 @@ end = struct let get_args (x:expr) = let n = get_num_args x in let f i = Z3native.get_app_arg (gc x) x i in - mk_list f n + List.init n f let update (x:expr) (args:expr list) = if AST.is_app x && List.length args <> get_num_args x then @@ -567,11 +554,11 @@ open Expr module Boolean = struct - let mk_sort = Z3native.mk_bool_sort + let mk_sort ctx = Z3native.mk_bool_sort ctx let mk_const (ctx:context) (name:Symbol.symbol) = Expr.mk_const ctx name (mk_sort ctx) let mk_const_s (ctx:context) (name:string) = mk_const ctx (Symbol.mk_string ctx name) - let mk_true = Z3native.mk_true - let mk_false = Z3native.mk_false + let mk_true ctx = Z3native.mk_true ctx + let mk_false ctx = Z3native.mk_false ctx let mk_val (ctx:context) (value:bool) = if value then mk_true ctx else mk_false ctx let mk_not = Z3native.mk_not let mk_ite = Z3native.mk_ite @@ -609,7 +596,7 @@ end module Quantifier = struct type quantifier = AST.ast - let gc = Z3native.context_of_ast + let gc a = Z3native.context_of_ast a let expr_of_quantifier q = q @@ -623,14 +610,14 @@ struct module Pattern = struct type pattern = Z3native.pattern - let gc = Z3native.context_of_ast + let gc a = Z3native.context_of_ast a let get_num_terms x = Z3native.get_pattern_num_terms (gc x) x let get_terms x = let n = get_num_terms x in let f i = Z3native.get_pattern (gc x) x i in - mk_list f n + List.init n f let to_string x = Z3native.pattern_to_string (gc x) x end @@ -648,26 +635,26 @@ struct let get_patterns x = let n = get_num_patterns x in let f i = Z3native.get_quantifier_pattern_ast (gc x) x i in - mk_list f n + List.init n f let get_num_no_patterns x = Z3native.get_quantifier_num_no_patterns (gc x) x let get_no_patterns x = let n = get_num_patterns x in let f i = Z3native.get_quantifier_no_pattern_ast (gc x) x i in - mk_list f n + List.init n f let get_num_bound x = Z3native.get_quantifier_num_bound (gc x) x let get_bound_variable_names x = let n = get_num_bound x in let f i = Z3native.get_quantifier_bound_name (gc x) x i in - mk_list f n + List.init n f let get_bound_variable_sorts x = let n = get_num_bound x in let f i = Z3native.get_quantifier_bound_sort (gc x) x i in - mk_list f n + List.init n f let get_body x = Z3native.get_quantifier_body (gc x) x let mk_bound = Z3native.mk_bound @@ -746,7 +733,7 @@ end module Z3Array = struct - let mk_sort = Z3native.mk_array_sort + let mk_sort ctx domain range = Z3native.mk_array_sort ctx domain range let is_store x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_STORE let is_select x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_SELECT let is_constant_array x = AST.is_app x && FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_CONST_ARRAY @@ -806,7 +793,7 @@ end module FiniteDomain = struct - let mk_sort = Z3native.mk_finite_domain_sort + let mk_sort ctx s size = Z3native.mk_finite_domain_sort ctx s size let mk_sort_s ctx name size = mk_sort ctx (Symbol.mk_string ctx name) size let is_finite_domain (x:expr) = @@ -849,7 +836,7 @@ struct let get_column_sorts (x:Sort.sort) = let n = get_arity x in let f i = Z3native.get_relation_column (Sort.gc x) x i in - mk_list f n + List.init n f end @@ -932,12 +919,12 @@ struct let get_constructors (x:Sort.sort) = let n = get_num_constructors x in let f i = Z3native.get_datatype_sort_constructor (Sort.gc x) x i in - mk_list f n + List.init n f let get_recognizers (x:Sort.sort) = let n = (get_num_constructors x) in let f i = Z3native.get_datatype_sort_recognizer (Sort.gc x) x i in - mk_list f n + List.init n f let get_accessors (x:Sort.sort) = let n = (get_num_constructors x) in @@ -945,8 +932,8 @@ struct let fd = Z3native.get_datatype_sort_constructor (Sort.gc x) x i in let ds = Z3native.get_domain_size (FuncDecl.gc fd) fd in let g j = Z3native.get_datatype_sort_constructor_accessor (Sort.gc x) x i j in - mk_list g ds) in - mk_list f n + List.init ds g) in + List.init n f end @@ -962,21 +949,21 @@ struct let get_const_decls (x:Sort.sort) = let n = Z3native.get_datatype_sort_num_constructors (Sort.gc x) x in let f i = Z3native.get_datatype_sort_constructor (Sort.gc x) x i in - mk_list f n + List.init n f let get_const_decl (x:Sort.sort) (inx:int) = Z3native.get_datatype_sort_constructor (Sort.gc x) x inx let get_consts (x:Sort.sort) = let n = Z3native.get_datatype_sort_num_constructors (Sort.gc x) x in let f i = Expr.mk_const_f (Sort.gc x) (get_const_decl x i) in - mk_list f n + List.init n f let get_const (x:Sort.sort) (inx:int) = Expr.mk_const_f (Sort.gc x) (get_const_decl x inx) let get_tester_decls (x:Sort.sort) = let n = Z3native.get_datatype_sort_num_constructors (Sort.gc x) x in let f i = Z3native.get_datatype_sort_recognizer (Sort.gc x) x i in - mk_list f n + List.init n f let get_tester_decl (x:Sort.sort) (inx:int) = Z3native.get_datatype_sort_recognizer (Sort.gc x) x inx end @@ -1010,8 +997,8 @@ struct let get_field_decls (x:Sort.sort) = let n = get_num_fields x in - let f i =Z3native.get_tuple_sort_field_decl (Sort.gc x) x i in - mk_list f n + let f i = Z3native.get_tuple_sort_field_decl (Sort.gc x) x i in + List.init n f end @@ -1043,7 +1030,7 @@ struct module Integer = struct - let mk_sort = Z3native.mk_int_sort + let mk_sort ctx = Z3native.mk_int_sort ctx let get_int x = match Z3native.get_numeral_int (Expr.gc x) x with @@ -1070,7 +1057,7 @@ struct module Real = struct - let mk_sort = Z3native.mk_real_sort + let mk_sort ctx = Z3native.mk_real_sort ctx let get_numerator x = Z3native.get_numerator (Expr.gc x) x let get_denominator x = Z3native.get_denominator (Expr.gc x) x @@ -1467,7 +1454,7 @@ end module Goal = struct type goal = Z3native.goal - let gc = Z3native.context_of_goal + let gc g = Z3native.context_of_goal g let get_precision (x:goal) = goal_prec_of_int (Z3native.goal_precision (gc x) x) let is_precise (x:goal) = (get_precision x) = GOAL_PRECISE @@ -1486,7 +1473,7 @@ struct let get_formulas (x:goal) = let n = get_size x in let f i = Z3native.goal_formula (gc x) x i in - mk_list f n + List.init n f let get_num_exprs (x:goal) = Z3native.goal_num_exprs (gc x) x let is_decided_sat (x:goal) = Z3native.goal_is_decided_sat (gc x) x @@ -1527,17 +1514,17 @@ end module Model = struct type model = Z3native.model - let gc = Z3native.context_of_model + let gc m = Z3native.context_of_model m module FuncInterp = struct type func_interp = Z3native.func_interp - let gc = Z3native.context_of_func_interp + let gc f = Z3native.context_of_func_interp f module FuncEntry = struct type func_entry = Z3native.func_entry - let gc = Z3native.context_of_func_entry + let gc f = Z3native.context_of_func_entry f let get_value (x:func_entry) = Z3native.func_entry_get_value (gc x) x let get_num_args (x:func_entry) = Z3native.func_entry_get_num_args (gc x) x @@ -1545,7 +1532,7 @@ struct let get_args (x:func_entry) = let n = get_num_args x in let f i = Z3native.func_entry_get_arg (gc x) x i in - mk_list f n + List.init n f let to_string (x:func_entry) = let a = get_args x in @@ -1558,7 +1545,7 @@ struct let get_entries (x:func_interp) = let n = get_num_entries x in let f i = Z3native.func_interp_get_entry (gc x) x i in - mk_list f n + List.init n f let get_else (x:func_interp) = Z3native.func_interp_get_else (gc x) x @@ -1614,21 +1601,24 @@ struct let get_const_decls (x:model) = let n = (get_num_consts x) in let f i = Z3native.model_get_const_decl (gc x) x i in - mk_list f n + List.init n f let get_num_funcs (x:model) = Z3native.model_get_num_funcs (gc x) x let get_func_decls (x:model) = let n = (get_num_funcs x) in let f i = Z3native.model_get_func_decl (gc x) x i in - mk_list f n + List.init n f let get_decls (x:model) = let n_funcs = get_num_funcs x in let n_consts = get_num_consts x in let f i = Z3native.model_get_func_decl (gc x) x i in let g i = Z3native.model_get_const_decl (gc x) x i in - (mk_list f n_funcs) @ (mk_list g n_consts) + List.init (n_funcs + n_consts) (fun i -> + if i < n_funcs then f i + else g i + ) let eval (x:model) (t:expr) (completion:bool) = match Z3native.model_eval (gc x) x t completion with @@ -1641,7 +1631,7 @@ struct let get_sorts (x:model) = let n = get_num_sorts x in let f i = Z3native.model_get_sort (gc x) x i in - mk_list f n + List.init n f let sort_universe (x:model) (s:Sort.sort) = let av = Z3native.model_get_sort_universe (gc x) x s in @@ -1656,12 +1646,12 @@ struct type probe = Z3native.probe let apply (x:probe) (g:Goal.goal) = Z3native.probe_apply (gc x) x g - let get_num_probes = Z3native.get_num_probes + let get_num_probes ctx = Z3native.get_num_probes ctx let get_probe_names (ctx:context) = let n = get_num_probes ctx in let f i = Z3native.get_probe_name ctx i in - mk_list f n + List.init n f let get_probe_description = Z3native.probe_get_descr let mk_probe = Z3native.mk_probe @@ -1680,19 +1670,19 @@ end module Tactic = struct type tactic = Z3native.tactic - let gc = Z3native.context_of_tactic + let gc t = Z3native.context_of_tactic t module ApplyResult = struct type apply_result = Z3native.apply_result - let gc = Z3native.context_of_apply_result + let gc a = Z3native.context_of_apply_result a let get_num_subgoals (x:apply_result) = Z3native.apply_result_get_num_subgoals (gc x) x let get_subgoals (x:apply_result) = let n = get_num_subgoals x in let f i = Z3native.apply_result_get_subgoal (gc x) x i in - mk_list f n + List.init n f let get_subgoal (x:apply_result) (i:int) = Z3native.apply_result_get_subgoal (gc x) x i let to_string (x:apply_result) = Z3native.apply_result_to_string (gc x) x @@ -1706,23 +1696,26 @@ struct | None -> Z3native.tactic_apply (gc x) x g | Some pn -> Z3native.tactic_apply_ex (gc x) x g pn - let get_num_tactics = Z3native.get_num_tactics + let get_num_tactics ctx = Z3native.get_num_tactics ctx let get_tactic_names (ctx:context) = let n = get_num_tactics ctx in let f i = Z3native.get_tactic_name ctx i in - mk_list f n + List.init n f let get_tactic_description = Z3native.tactic_get_descr let mk_tactic = Z3native.mk_tactic let and_then (ctx:context) (t1:tactic) (t2:tactic) (ts:tactic list) = - let f p c = (match p with - | None -> Some c - | Some(x) -> Some (Z3native.tactic_and_then ctx c x)) in - match (List.fold_left f None ts) with + let f p c = + match p with + | None -> Some c + | Some x -> Some (Z3native.tactic_and_then ctx c x) + in + match List.fold_left f None ts with | None -> Z3native.tactic_and_then ctx t1 t2 - | Some(x) -> let o = Z3native.tactic_and_then ctx t2 x in + | Some x -> + let o = Z3native.tactic_and_then ctx t2 x in Z3native.tactic_and_then ctx t1 o let or_else = Z3native.tactic_or_else @@ -1744,18 +1737,18 @@ end module Simplifier = struct type simplifier = Z3native.simplifier - let gc = Z3native.context_of_simplifier + let gc s = Z3native.context_of_simplifier s let get_help (x:simplifier) = Z3native.simplifier_get_help (gc x) x let get_param_descrs (x:simplifier) = Z3native.simplifier_get_param_descrs (gc x) x - let get_num_simplifiers = Z3native.get_num_simplifiers + let get_num_simplifiers ctx = Z3native.get_num_simplifiers ctx let get_simplifier_names (ctx:context) = let n = get_num_simplifiers ctx in let f i = Z3native.get_simplifier_name ctx i in - mk_list f n + List.init n f let get_simplifier_description = Z3native.simplifier_get_descr @@ -1778,7 +1771,7 @@ end module Statistics = struct type statistics = Z3native.stats - let gc = Z3native.context_of_stats + let gc s = Z3native.context_of_stats s module Entry = struct @@ -1822,12 +1815,12 @@ struct else Entry.create_sd k (Z3native.stats_get_double_value (gc x) x i) in - mk_list f n + List.init n f let get_keys (x:statistics) = let n = get_size x in let f i = Z3native.stats_get_key (gc x) x i in - mk_list f n + List.init n f let get (x:statistics) (key:string) = try Some(List.find (fun c -> Entry.get_key c = key) (get_entries x)) with @@ -1842,7 +1835,7 @@ module Solver = struct type solver = Z3native.solver type status = UNSATISFIABLE | UNKNOWN | SATISFIABLE - let gc = Z3native.context_of_solver + let gc s = Z3native.context_of_solver s let string_of_status (s:status) = match s with | UNSATISFIABLE -> "unsatisfiable" @@ -1923,7 +1916,7 @@ end module Fixedpoint = struct type fixedpoint = Z3native.fixedpoint - let gc = Z3native.context_of_fixedpoint + let gc f = Z3native.context_of_fixedpoint f let get_help x = Z3native.fixedpoint_get_help (gc x) x let set_parameters x = Z3native.fixedpoint_set_params (gc x) x @@ -2055,22 +2048,22 @@ struct formula let parse_smtlib2_string (ctx:context) (str:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = - let csn = List.length sort_names in let cs = List.length sorts in - let cdn = List.length decl_names in let cd = List.length decls in - if csn <> cs || cdn <> cd then + if List.compare_length_with sort_names cs <> 0 + || List.compare_length_with decl_names cd <> 0 + then raise (Error "Argument size mismatch") else Z3native.parse_smtlib2_string ctx str cs sort_names sorts cd decl_names decls let parse_smtlib2_file (ctx:context) (file_name:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = - let csn = List.length sort_names in let cs = List.length sorts in - let cdn = List.length decl_names in let cd = List.length decls in - if csn <> cs || cdn <> cd then + if List.compare_length_with sort_names cs <> 0 + || List.compare_length_with decl_names cd <> 0 + then raise (Error "Argument size mismatch") else Z3native.parse_smtlib2_file ctx file_name @@ -2082,7 +2075,7 @@ module RCF = struct type rcf_num = Z3native.rcf_num - let del (ctx:context) (a:rcf_num) = Z3native.rcf_del ctx a + let del (ctx:context) (a:rcf_num) : unit = Z3native.rcf_del ctx a let del_list (ctx:context) (ns:rcf_num list) = List.iter (fun a -> Z3native.rcf_del ctx a) ns let mk_rational (ctx:context) (v:string) = Z3native.rcf_mk_rational ctx v let mk_small_int (ctx:context) (v:int) = Z3native.rcf_mk_small_int ctx v @@ -2093,7 +2086,14 @@ struct let mk_roots (ctx:context) (a:rcf_num list) = let n, r = Z3native.rcf_mk_roots ctx (List.length a) a in - List.init n (fun x -> List.nth r x) + let _i, l = + (* keep only the first `n` elements of the list `r` *) + List.fold_left (fun (i, acc) x -> + if i = 0 then i, acc + else (i - 1, x :: acc) + ) (n, []) r + in + List.rev l let add (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_add ctx a b let sub (ctx:context) (a:rcf_num) (b:rcf_num) = Z3native.rcf_sub ctx a b diff --git a/src/api/ml/z3native.ml.pre b/src/api/ml/z3native.ml.pre index 1d75d5d1e..fe4e8a194 100644 --- a/src/api/ml/z3native.ml.pre +++ b/src/api/ml/z3native.ml.pre @@ -4,36 +4,36 @@ open Z3enums (**/**) type ptr -and symbol = ptr -and config = ptr -and context = ptr -and ast = ptr -and app = ast -and sort = ast -and func_decl = ast -and pattern = ast -and model = ptr -and literals = ptr -and constructor = ptr -and constructor_list = ptr -and solver = ptr -and solver_callback = ptr -and goal = ptr -and tactic = ptr -and simplifier = ptr -and params = ptr -and parser_context = ptr -and probe = ptr -and stats = ptr -and ast_vector = ptr -and ast_map = ptr -and apply_result = ptr -and func_interp = ptr -and func_entry = ptr -and fixedpoint = ptr -and optimize = ptr -and param_descrs = ptr -and rcf_num = ptr +type symbol = ptr +type config = ptr +type context = ptr +type ast = ptr +type app = ast +type sort = ast +type func_decl = ast +type pattern = ast +type model = ptr +type literals = ptr +type constructor = ptr +type constructor_list = ptr +type solver = ptr +type solver_callback = ptr +type goal = ptr +type tactic = ptr +type simplifier = ptr +type params = ptr +type parser_context = ptr +type probe = ptr +type stats = ptr +type ast_vector = ptr +type ast_map = ptr +type apply_result = ptr +type func_interp = ptr +type func_entry = ptr +type fixedpoint = ptr +type optimize = ptr +type param_descrs = ptr +type rcf_num = ptr external set_internal_error_handler : ptr -> unit = "n_set_internal_error_handler" From 57c20be6ebeb9b21276beff145e68d7e095bcd02 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 4 Mar 2024 14:34:02 +0000 Subject: [PATCH 04/69] fix #7143: type punning in test --- src/test/hwf.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/hwf.cpp b/src/test/hwf.cpp index 8a019ec02..b81a9cef3 100644 --- a/src/test/hwf.cpp +++ b/src/test/hwf.cpp @@ -103,7 +103,9 @@ static void bug_to_rational() { static void bug_is_int() { unsigned raw_val[2] = { 2147483648u, 1077720461u }; - double val = *(double*)(raw_val); + double val; + static_assert(sizeof(raw_val) == sizeof(val)); + memcpy(&val, raw_val, sizeof(val)); std::cout << val << "\n"; hwf_manager m; hwf a; From 4050a43f2f81f11d7474576a02d878adb44f5f4b Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Mon, 4 Mar 2024 17:28:50 -0800 Subject: [PATCH 05/69] Add arm64 for linux python wheels to nightly (#7145) --- scripts/nightly.yaml | 45 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index da95812d2..77ca31458 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -194,6 +194,41 @@ stages: artifactName: 'ManyLinuxBuild' targetPath: $(Build.ArtifactStagingDirectory) + - job: LinuxBuildsArm64 + displayName: "ManyLinux ARM64 build" + variables: + name: ManyLinux + python: "/opt/python/cp37-cp37m/bin/python" + pool: + vmImage: "ubuntu-latest" + container: "quay.io/pypa/manylinux2014_x86_64:latest" + steps: + - task: PythonScript@0 + displayName: Build + inputs: + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --nodotnet --nojava --arch=arm64 + pythonInterpreter: $(python) + - script: git clone https://github.com/z3prover/z3test z3test + displayName: 'Clone z3test' + - task: PythonScript@0 + displayName: Test + inputs: + scriptSource: 'filepath' + scriptPath: z3test/scripts/test_benchmarks.py + arguments: build-dist/z3 z3test/regressions/smt2 + pythonInterpreter: $(python) + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'ManyLinuxBuildArm64' + targetPath: $(Build.ArtifactStagingDirectory) + - template: build-win-signed.yml parameters: ReleaseVersion: $(ReleaseVersion) @@ -459,6 +494,10 @@ stages: inputs: artifactName: 'ManyLinuxBuild' targetPath: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: 'ManyLinuxBuildArm64' + targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: artifactName: 'macOsBuild' @@ -469,14 +508,16 @@ stages: targetPath: $(Agent.TempDirectory) - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-x64-bin; cd libc-x64-bin; unzip ../*x64-glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-arm64-bin; cd libc-arm64-bin; unzip ../*arm64-glibc*.zip # - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip - script: python3 -m pip install --user -U setuptools wheel - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel # - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel From 77a07bb791361ad9b0a2ba7106e429e96b9c3c59 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Mar 2024 21:14:19 -0800 Subject: [PATCH 06/69] detect arm64 for manylinux setup Signed-off-by: Nikolaj Bjorner --- src/api/python/setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index c3f65f848..8a8a49dc5 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -297,6 +297,8 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: elif distos == 'glibc': if arch == 'x64': plat_name = 'manylinux2014_x86_64' + elif arch == 'arm64': + plat_name = 'manylinux2014_arm64' else: plat_name = 'manylinux2014_i686' elif distos == 'linux' and os_id == 'alpine': From 7694bca5f4938b6c331cef6b821bcefb2dce9a0a Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Tue, 5 Mar 2024 11:27:43 -0800 Subject: [PATCH 07/69] For many linux build, use aarch64 instead of arm64 (#7147) --- scripts/nightly.yaml | 14 +++++++------- src/api/python/setup.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 77ca31458..9b573a675 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -194,8 +194,8 @@ stages: artifactName: 'ManyLinuxBuild' targetPath: $(Build.ArtifactStagingDirectory) - - job: LinuxBuildsArm64 - displayName: "ManyLinux ARM64 build" + - job: LinuxBuildsAarch64 + displayName: "ManyLinux AARCH64 build" variables: name: ManyLinux python: "/opt/python/cp37-cp37m/bin/python" @@ -208,7 +208,7 @@ stages: inputs: scriptSource: 'filepath' scriptPath: scripts/mk_unix_dist.py - arguments: --nodotnet --nojava --arch=arm64 + arguments: --nodotnet --nojava --arch=aarch64 pythonInterpreter: $(python) - script: git clone https://github.com/z3prover/z3test z3test displayName: 'Clone z3test' @@ -226,7 +226,7 @@ stages: targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@0 inputs: - artifactName: 'ManyLinuxBuildArm64' + artifactName: 'ManyLinuxBuildAarch64' targetPath: $(Build.ArtifactStagingDirectory) - template: build-win-signed.yml @@ -496,7 +496,7 @@ stages: targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: - artifactName: 'ManyLinuxBuildArm64' + artifactName: 'ManyLinuxBuildAarch64' targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: @@ -509,7 +509,7 @@ stages: - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir libc-x64-bin; cd libc-x64-bin; unzip ../*x64-glibc*.zip - - script: cd $(Agent.TempDirectory); mkdir libc-arm64-bin; cd libc-arm64-bin; unzip ../*arm64-glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-aarch64-bin; cd libc-aarch64-bin; unzip ../*aarch64-glibc*.zip # - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip @@ -517,7 +517,7 @@ stages: - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-aarch64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel # - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 8a8a49dc5..97046dc91 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -297,8 +297,8 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: elif distos == 'glibc': if arch == 'x64': plat_name = 'manylinux2014_x86_64' - elif arch == 'arm64': - plat_name = 'manylinux2014_arm64' + elif arch == 'aarch64': + plat_name = 'manylinux2014_aarch64' else: plat_name = 'manylinux2014_i686' elif distos == 'linux' and os_id == 'alpine': From 10687082f11c84f0133ddac17f51d5a87d87afce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Mar 2024 12:25:31 -0800 Subject: [PATCH 08/69] Revert "For many linux build, use aarch64 instead of arm64 (#7147)" (#7148) This reverts commit 7694bca5f4938b6c331cef6b821bcefb2dce9a0a. --- scripts/nightly.yaml | 14 +++++++------- src/api/python/setup.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 9b573a675..77ca31458 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -194,8 +194,8 @@ stages: artifactName: 'ManyLinuxBuild' targetPath: $(Build.ArtifactStagingDirectory) - - job: LinuxBuildsAarch64 - displayName: "ManyLinux AARCH64 build" + - job: LinuxBuildsArm64 + displayName: "ManyLinux ARM64 build" variables: name: ManyLinux python: "/opt/python/cp37-cp37m/bin/python" @@ -208,7 +208,7 @@ stages: inputs: scriptSource: 'filepath' scriptPath: scripts/mk_unix_dist.py - arguments: --nodotnet --nojava --arch=aarch64 + arguments: --nodotnet --nojava --arch=arm64 pythonInterpreter: $(python) - script: git clone https://github.com/z3prover/z3test z3test displayName: 'Clone z3test' @@ -226,7 +226,7 @@ stages: targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@0 inputs: - artifactName: 'ManyLinuxBuildAarch64' + artifactName: 'ManyLinuxBuildArm64' targetPath: $(Build.ArtifactStagingDirectory) - template: build-win-signed.yml @@ -496,7 +496,7 @@ stages: targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: - artifactName: 'ManyLinuxBuildAarch64' + artifactName: 'ManyLinuxBuildArm64' targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: @@ -509,7 +509,7 @@ stages: - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir libc-x64-bin; cd libc-x64-bin; unzip ../*x64-glibc*.zip - - script: cd $(Agent.TempDirectory); mkdir libc-aarch64-bin; cd libc-aarch64-bin; unzip ../*aarch64-glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-arm64-bin; cd libc-arm64-bin; unzip ../*arm64-glibc*.zip # - script: cd $(Agent.TempDirectory); mkdir musl-bin; cd musl-bin; unzip ../*-linux.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip @@ -517,7 +517,7 @@ stages: - script: cd src/api/python; python3 setup.py sdist # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-aarch64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel # - script: cd src/api/python; echo $(Agent.TempDirectory)/musl-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 97046dc91..8a8a49dc5 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -297,8 +297,8 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: elif distos == 'glibc': if arch == 'x64': plat_name = 'manylinux2014_x86_64' - elif arch == 'aarch64': - plat_name = 'manylinux2014_aarch64' + elif arch == 'arm64': + plat_name = 'manylinux2014_arm64' else: plat_name = 'manylinux2014_i686' elif distos == 'linux' and os_id == 'alpine': From f39756c74b3736a122ae93c72a805f63fb045084 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Feb 2024 16:34:26 +0700 Subject: [PATCH 09/69] initial stab at new bv-sls based on repair actions --- src/ast/sls/CMakeLists.txt | 7 +- src/ast/sls/bv_sls.cpp | 160 +++++++ src/ast/sls/bv_sls.h | 99 ++++ src/ast/sls/bv_sls_eval.cpp | 821 ++++++++++++++++++++++++++++++++++ src/ast/sls/bv_sls_eval.h | 134 ++++++ src/ast/sls/bv_sls_fixed.cpp | 386 ++++++++++++++++ src/ast/sls/bv_sls_fixed.h | 52 +++ src/ast/sls/bv_sls_terms.cpp | 138 ++++++ src/ast/sls/bv_sls_terms.h | 70 +++ src/ast/sls/sls_engine.cpp | 13 - src/ast/sls/sls_engine.h | 35 +- src/ast/sls/sls_powers.h | 1 + src/ast/sls/sls_stats.h | 48 ++ src/ast/sls/sls_valuation.cpp | 127 ++++++ src/ast/sls/sls_valuation.h | 116 +++++ src/tactic/sls/sls_tactic.cpp | 107 +++++ src/tactic/sls/sls_tactic.h | 9 + 17 files changed, 2278 insertions(+), 45 deletions(-) create mode 100644 src/ast/sls/bv_sls.cpp create mode 100644 src/ast/sls/bv_sls.h create mode 100644 src/ast/sls/bv_sls_eval.cpp create mode 100644 src/ast/sls/bv_sls_eval.h create mode 100644 src/ast/sls/bv_sls_fixed.cpp create mode 100644 src/ast/sls/bv_sls_fixed.h create mode 100644 src/ast/sls/bv_sls_terms.cpp create mode 100644 src/ast/sls/bv_sls_terms.h create mode 100644 src/ast/sls/sls_stats.h create mode 100644 src/ast/sls/sls_valuation.cpp create mode 100644 src/ast/sls/sls_valuation.h diff --git a/src/ast/sls/CMakeLists.txt b/src/ast/sls/CMakeLists.txt index 17b803cf3..24eaec4dc 100644 --- a/src/ast/sls/CMakeLists.txt +++ b/src/ast/sls/CMakeLists.txt @@ -1,7 +1,12 @@ z3_add_component(ast_sls SOURCES bvsls_opt_engine.cpp - sls_engine.cpp + bv_sls.cpp + bv_sls_eval.cpp + bv_sls_fixed.cpp + bv_sls_terms.cpp + sls_engine.cpp + sls_valuation.cpp COMPONENT_DEPENDENCIES ast converters diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp new file mode 100644 index 000000000..90058607e --- /dev/null +++ b/src/ast/sls/bv_sls.cpp @@ -0,0 +1,160 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls.cpp + +Abstract: + + A Stochastic Local Search (SLS) engine + Uses invertibility conditions, + interval annotations + don't care annotations + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ + +#include "ast/sls/bv_sls.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" + +namespace bv { + + sls::sls(ast_manager& m): + m(m), + bv(m), + m_terms(m), + m_eval(m) + {} + + void sls::init() { + m_terms.init(); + } + + void sls::init_eval(std::function& eval) { + m_eval.init_eval(m_terms.assertions(), eval); + for (auto* e : m_terms.assertions()) { + if (!m_eval.bval0(e)) { + m_eval.set(e, true); + m_repair_down.insert(e->get_id()); + } + } + m_eval.init_fixed(m_terms.assertions()); + } + + lbool sls::operator()() { + // init and init_eval were invoked. + unsigned& n = m_stats.m_moves; + n = 0; + for (; n < m_config.m_max_repairs && m.inc(); ++n) { + if (!m_repair_down.empty()) { + unsigned index = m_rand(m_repair_down.size()); + unsigned expr_id = m_repair_down.elem_at(index); + auto e = m_terms.term(expr_id); + if (eval_is_correct(e)) + m_repair_down.remove(expr_id); + else + try_repair_down(e); + } + else if (!m_repair_up.empty()) { + unsigned index = m_rand(m_repair_up.size()); + unsigned expr_id = m_repair_up.elem_at(index); + auto e = m_terms.term(expr_id); + if (eval_is_correct(e)) + m_repair_up.remove(expr_id); + else + try_repair_up(e); + } + else + return l_true; + } + return l_undef; + } + + bool sls::try_repair_down(app* e) { + IF_VERBOSE(20, verbose_stream() << "d " << mk_bounded_pp(e, m, 1) << "\n"); + unsigned n = e->get_num_args(); + unsigned s = m_rand(n); + for (unsigned i = 0; i < n; ++i) + if (try_repair_down(e, (i + s) % n)) + return true; + return false; + } + + bool sls::try_repair_down(app* e, unsigned i) { + expr* child = e->get_arg(i); + bool was_repaired = m_eval.try_repair(e, i); + if (was_repaired) { + m_repair_down.insert(child->get_id()); + for (auto p : m_terms.parents(child)) + m_repair_up.insert(p->get_id()); + } + return was_repaired; + } + + bool sls::try_repair_up(app* e) { + IF_VERBOSE(20, verbose_stream() << "u " << mk_bounded_pp(e, m, 1) << "\n"); + m_repair_up.remove(e->get_id()); + if (m_terms.is_assertion(e)) { + m_repair_down.insert(e->get_id()); + return false; + } + m_eval.repair_up(e); + for (auto p : m_terms.parents(e)) + m_repair_up.insert(p->get_id()); + + return true; + } + + bool sls::eval_is_correct(app* e) { + if (m.is_bool(e)) + return m_eval.bval0(e) == m_eval.bval1(e); + if (bv.is_bv(e)) + return 0 == memcmp(m_eval.wval0(e).bits.data(), m_eval.wval1(e).data(), m_eval.wval0(e).nw * 8); + UNREACHABLE(); + return false; + } + + model_ref sls::get_model() { + model_ref mdl = alloc(model, m); + m_eval.sort_assertions(m_terms.assertions()); + for (expr* e : m_todo) { + if (!is_uninterp_const(e)) + continue; + auto f = to_app(e)->get_decl(); + if (m.is_bool(e)) + mdl->register_decl(f, m.mk_bool_val(m_eval.bval0(e))); + else if (bv.is_bv(e)) { + auto const& v = m_eval.wval0(e); + rational n; + v.get_value(v.bits, n); + mdl->register_decl(f, bv.mk_numeral(n, v.bw)); + } + } + return mdl; + } + + std::ostream& sls::display(std::ostream& out) { + auto& terms = m_eval.sort_assertions(m_terms.assertions()); + for (expr* e : terms) { + out << e->get_id() << ": " << mk_bounded_pp(e, m, 1) << " "; + if (m_eval.is_fixed0(e)) + out << "f "; + if (m_repair_down.contains(e->get_id())) + out << "d "; + if (m_repair_up.contains(e->get_id())) + out << "u "; + if (bv.is_bv(e)) + out << m_eval.wval0(e); + else if (m.is_bool(e)) + out << (m_eval.bval0(e)?"T":"F"); + out << "\n"; + } + terms.reset(); + return out; + } +} diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h new file mode 100644 index 000000000..6acaf483c --- /dev/null +++ b/src/ast/sls/bv_sls.h @@ -0,0 +1,99 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls.h + +Abstract: + + A Stochastic Local Search (SLS) engine + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ +#pragma once + +#include "util/lbool.h" +#include "util/params.h" +#include "util/scoped_ptr_vector.h" +#include "util/uint_set.h" +#include "ast/ast.h" +#include "ast/sls/sls_stats.h" +#include "ast/sls/sls_powers.h" +#include "ast/sls/sls_valuation.h" +#include "ast/sls/bv_sls_terms.h" +#include "ast/sls/bv_sls_eval.h" +#include "ast/bv_decl_plugin.h" +#include "model/model.h" + +namespace bv { + + + class sls { + + struct config { + unsigned m_max_restarts = 1000; + unsigned m_max_repairs = 100000; + }; + + ast_manager& m; + bv_util bv; + sls_terms m_terms; + sls_eval m_eval; + sls_stats m_stats; + indexed_uint_set m_repair_down, m_repair_up; + ptr_vector m_todo; + random_gen m_rand; + config m_config; + + + bool eval_is_correct(app* e); + bool try_repair_down(app* e); + bool try_repair_up(app* e); + + bool try_repair_down(app* e, unsigned i); + + public: + sls(ast_manager& m); + + /** + * Add constraints + */ + void assert_expr(expr* e) { m_terms.assert_expr(e); } + + /* + * Invoke init after all expressions are asserted. + * No other expressions can be asserted after init. + */ + void init(); + + /** + * Invoke init_eval to initialize, or re-initialize, values of + * uninterpreted constants. + */ + void init_eval(std::function& eval); + + /** + * Run (bounded) local search to find feasible assignments. + */ + lbool operator()(); + + void updt_params(params_ref const& p) {} + void collect_statistics(statistics & st) const { m_stats.collect_statistics(st); } + void reset_statistics() { m_stats.reset(); } + + sls_stats const& get_stats() const { return m_stats; } + + std::ostream& display(std::ostream& out); + + /** + * Retrieve valuation + */ + sls_valuation const& wval(expr* e) const { return m_eval.wval0(e); } + + model_ref get_model(); + }; +} diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp new file mode 100644 index 000000000..990d87dbb --- /dev/null +++ b/src/ast/sls/bv_sls_eval.cpp @@ -0,0 +1,821 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls_eval.cpp + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ + +#include "ast/ast_pp.h" +#include "ast/sls/bv_sls.h" + +namespace bv { + + sls_eval::sls_eval(ast_manager& m): + m(m), + bv(m), + m_fix(*this) + {} + + void sls_eval::init_eval(expr_ref_vector const& es, std::function const& eval) { + sort_assertions(es); + for (expr* e : m_todo) { + if (!is_app(e)) + continue; + app* a = to_app(e); + if (bv.is_bv(e)) + add_bit_vector(e); + if (a->get_family_id() == basic_family_id) + init_eval_basic(a); + else if (a->get_family_id() == bv.get_family_id()) + init_eval_bv(a); + else if (is_uninterp(e)) { + if (bv.is_bv(e)) { + auto& v = wval0(e); + for (unsigned i = 0; i < v.bw; ++i) + v.set(v.bits, i, eval(e, i)); + } + else if (m.is_bool(e)) + m_eval.setx(e->get_id(), eval(e, 0), false); + } + else { + TRACE("sls", tout << "Unhandled expression " << mk_pp(e, m) << "\n"); + } + } + m_todo.reset(); + } + + /** + * Sort all sub-expressions by depth, smallest first. + */ + ptr_vector& sls_eval::sort_assertions(expr_ref_vector const& es) { + expr_fast_mark1 mark; + for (expr* e : es) { + if (!mark.is_marked(e)) { + mark.mark(e); + m_todo.push_back(e); + } + } + for (unsigned i = 0; i < m_todo.size(); ++i) { + auto e = m_todo[i]; + if (!is_app(e)) + continue; + for (expr* arg : *to_app(e)) { + if (!mark.is_marked(arg)) { + mark.mark(arg); + m_todo.push_back(arg); + } + } + } + std::stable_sort(m_todo.begin(), m_todo.end(), [&](expr* a, expr* b) { return get_depth(a) < get_depth(b); }); + return m_todo; + } + + bool sls_eval::add_bit_vector(expr* e) { + auto bw = bv.get_bv_size(e); + m_values0.reserve(e->get_id() + 1); + if (m_values0.get(e->get_id())) + return false; + m_values1.reserve(e->get_id() + 1); + m_values0.set(e->get_id(), alloc_valuation(bw)); + m_values1.set(e->get_id(), alloc_valuation(bw)); + return true; + } + + sls_valuation* sls_eval::alloc_valuation(unsigned bit_width) { + auto* r = alloc(sls_valuation, bit_width); + while (m_tmp.size() < r->nw) { + m_tmp.push_back(0); + m_tmp2.push_back(0); + m_tmp2.push_back(0); + m_zero.push_back(0); + } + return r; + } + + void sls_eval::init_eval_basic(app* e) { + auto id = e->get_id(); + if (m.is_bool(e)) + m_eval.setx(id, bval1(e), false); + else if (m.is_ite(e)) { + SASSERT(bv.is_bv(e->get_arg(1))); + auto& val = wval0(e); + auto& val_th = wval0(e->get_arg(1)); + auto& val_el = wval0(e->get_arg(2)); + if (bval0(e->get_arg(0))) + val.set(val_th.bits); + else + val.set(val_el.bits); + } + else { + UNREACHABLE(); + } + } + + void sls_eval::init_eval_bv(app* e) { + if (bv.is_bv(e)) { + auto& v = wval0(e); + v.set(wval1(e)); + } + else if (m.is_bool(e)) + m_eval.setx(e->get_id(), bval1_bv(e), false); + } + + bool sls_eval::bval1_basic(app* e) const { + SASSERT(m.is_bool(e)); + SASSERT(e->get_family_id() == basic_family_id); + + auto id = e->get_id(); + switch (e->get_decl_kind()) { + case OP_TRUE: + return true; + case OP_FALSE: + return false; + case OP_AND: + return all_of(*to_app(e), [&](expr* arg) { return bval0(arg); }); + case OP_OR: + return any_of(*to_app(e), [&](expr* arg) { return bval0(arg); }); + case OP_NOT: + return !bval0(e->get_arg(0)); + case OP_XOR: { + bool r = false; + for (auto* arg : *to_app(e)) + r ^= bval0(arg); + return r; + } + case OP_IMPLIES: { + auto a = e->get_arg(0); + auto b = e->get_arg(1); + return !bval0(a) || bval0(b); + } + case OP_ITE: { + auto c = bval0(e->get_arg(0)); + return bval0(c ? e->get_arg(1) : e->get_arg(2)); + } + case OP_EQ: { + auto a = e->get_arg(0); + auto b = e->get_arg(1); + if (m.is_bool(a)) + return bval0(a) == bval0(b); + else if (bv.is_bv(a)) { + auto const& va = wval0(a); + auto const& vb = wval0(b); + return va.eq(vb); + } + UNREACHABLE(); + break; + } + default: + UNREACHABLE(); + } + UNREACHABLE(); + return false; + } + + bool sls_eval::bval1_bv(app* e) const { + SASSERT(m.is_bool(e)); + SASSERT(e->get_family_id() == bv.get_fid()); + + auto ucompare = [&](std::function const& f) { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + return f(mpn.compare(a.bits.data(), a.nw, b.bits.data(), b.nw)); + }; + + // x x + 2^{bw-1} const& f) { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + unsigned c; + a.set(m_zero, a.bw - 1, true); + mpn.add(a.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp.data(), a.nw, &c); + mpn.add(b.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp2.data(), a.nw, &c); + a.set(m_zero, a.bw - 1, false); + return f(mpn.compare(m_tmp.data(), a.nw, m_tmp2.data(), b.nw)); + }; + + auto umul_overflow = [&]() { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + mpn.mul(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp2.data()); + for (unsigned i = a.nw; i < 2 * a.nw; ++i) + if (m_tmp2[i] != 0) + return true; + for (unsigned i = a.bw; i < sizeof(digit_t) * 8 * a.nw; ++i) + if (a.get(m_tmp2, i)) + return true; + return false; + }; + + switch (e->get_decl_kind()) { + case OP_ULEQ: + return ucompare([](int i) { return i <= 0; }); + case OP_ULT: + return ucompare([](int i) { return i < 0; }); + case OP_UGT: + return ucompare([](int i) { return i > 0; }); + case OP_UGEQ: + return ucompare([](int i) { return i >= 0; }); + case OP_SLEQ: + return scompare([](int i) { return i <= 0; }); + case OP_SLT: + return scompare([](int i) { return i < 0; }); + case OP_SGT: + return scompare([](int i) { return i > 0; }); + case OP_SGEQ: + return scompare([](int i) { return i >= 0; }); + case OP_BIT2BOOL: { + expr* child; + unsigned idx; + VERIFY(bv.is_bit2bool(e, child, idx)); + auto& a = wval0(child); + return a.get(a.bits, idx); + } + case OP_BUMUL_NO_OVFL: + return !umul_overflow(); + case OP_BUMUL_OVFL: + return umul_overflow(); + case OP_BUADD_OVFL: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + digit_t c = 0; + mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp.data(), a.nw, &c); + return c != 0; + } + case OP_BNEG_OVFL: + case OP_BSADD_OVFL: + case OP_BSDIV_OVFL: + case OP_BSMUL_NO_OVFL: + case OP_BSMUL_NO_UDFL: + case OP_BSMUL_OVFL: + NOT_IMPLEMENTED_YET(); + break; + default: + UNREACHABLE(); + break; + } + return false; + } + + bool sls_eval::bval1(app* e) const { + if (e->get_family_id() == basic_family_id) + return bval1_basic(e); + if (e->get_family_id() == bv.get_fid()) + return bval1_bv(e); + SASSERT(is_uninterp_const(e)); + return bval0(e); + } + + svector& sls_eval::wval1(app* e) const { + auto& val = *m_values1[e->get_id()]; + wval1(e, val); + return val.bits; + } + + void sls_eval::wval1(app* e, sls_valuation& val) const { + SASSERT(bv.is_bv(e)); + if (m.is_ite(e)) { + SASSERT(bv.is_bv(e->get_arg(1))); + auto& val_th = wval0(e->get_arg(1)); + auto& val_el = wval0(e->get_arg(2)); + if (bval0(e->get_arg(0))) + val.set(val_th.bits); + else + val.set(val_el.bits); + return; + } + if (e->get_family_id() == null_family_id) { + val.set(wval0(e).bits); + return; + } + SASSERT(e->get_family_id() == bv.get_fid()); + switch (e->get_decl_kind()) { + case OP_BV_NUM: { + rational n; + VERIFY(bv.is_numeral(e, n)); + val.set_value(val.bits, n); + break; + } + case OP_BAND: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + for (unsigned i = 0; i < a.bw; ++i) + val.bits[i] = a.bits[i] & b.bits[i]; + break; + } + case OP_BOR: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + for (unsigned i = 0; i < a.bw; ++i) + val.bits[i] = a.bits[i] | b.bits[i]; + break; + } + case OP_BXOR: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + for (unsigned i = 0; i < a.bw; ++i) + val.bits[i] = a.bits[i] ^ b.bits[i]; + break; + } + case OP_BNAND: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + for (unsigned i = 0; i < a.bw; ++i) + val.bits[i] = ~(a.bits[i] & b.bits[i]); + break; + } + case OP_BADD: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + digit_t c; + mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, val.bits.data(), val.nw, &c); + break; + } + case OP_BMUL: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + mpn.mul(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp2.data()); + val.set(m_tmp2); + break; + } + case OP_CONCAT: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + for (unsigned i = 0; i < b.bw; ++i) + val.set(val.bits, i, b.get(b.bits, i)); + for (unsigned i = 0; i < a.bw; ++i) + val.set(val.bits, i + b.bw, a.get(a.bits, i)); + break; + } + case OP_EXTRACT: { + expr* child; + unsigned lo, hi; + VERIFY(bv.is_extract(e, lo, hi, child)); + auto const& a = wval0(child); + SASSERT(lo <= hi && hi + 1 <= a.bw && hi - lo + 1 == val.bw); + for (unsigned i = lo; i <= hi; ++i) + val.set(val.bits, i - lo, a.get(a.bits, i)); + break; + } + case OP_BNOT: { + auto& a = wval0(e->get_arg(0)); + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = ~a.bits[i]; + break; + } + case OP_BNEG: { + auto& a = wval0(e->get_arg(0)); + digit_t c; + mpn.sub(m_zero.data(), a.nw, a.bits.data(), a.nw, val.bits.data(), &c); + break; + } + case OP_BIT0: + val.set(val.bits, 0, false); + break; + case OP_BIT1: + val.set(val.bits, 0, true); + break; + case OP_BSHL: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + auto sh = b.to_nat(b.bits, b.bw); + if (sh == 0) { + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = a.bits[i]; + } + else if (sh >= b.bw) { + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = 0; + } + else { + for (unsigned i = 0; i < a.bw; ++i) + val.set(val.bits, i, i >= sh && b.get(b.bits, i - sh)); + } + break; + } + case OP_BLSHR: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + auto sh = b.to_nat(b.bits, b.bw); + if (sh == 0) { + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = a.bits[i]; + } + else if (sh >= b.bw) { + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = 0; + } + else { + for (unsigned i = 0; i < a.bw; ++i) + val.set(val.bits, i, i + sh < a.bw && b.get(b.bits, i + sh)); + } + break; + } + case OP_BASHR: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + auto sh = b.to_nat(b.bits, b.bw); + auto sign = a.get(a.bits, a.bw - 1); + if (sh == 0) { + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = a.bits[i]; + } + else if (sh >= b.bw) { + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = sign ? ~0 : 0; + } + else { + for (unsigned i = 0; i < a.bw; ++i) + val.set(val.bits, i, i + sh < a.bw && b.get(b.bits, i + sh)); + if (sign) + for (unsigned i = 0; i < sh; ++i) + val.set(val.bits, a.bw - i, true); + } + break; + } + case OP_BSDIV: + case OP_BSDIV_I: + case OP_BSDIV0: + case OP_BUDIV: + case OP_BUDIV_I: + case OP_BUDIV0: + case OP_BUREM: + case OP_BUREM_I: + case OP_BUREM0: + case OP_BSMOD: + case OP_BSMOD_I: + case OP_BSMOD0: + case OP_BREDAND: + case OP_BREDOR: + case OP_BXNOR: + case OP_INT2BV: + case OP_BCOMP: + NOT_IMPLEMENTED_YET(); + break; + case OP_BIT2BOOL: + case OP_BV2INT: + case OP_BNEG_OVFL: + case OP_BSADD_OVFL: + case OP_BUADD_OVFL: + case OP_BSDIV_OVFL: + case OP_BSMUL_NO_OVFL: + case OP_BSMUL_NO_UDFL: + case OP_BSMUL_OVFL: + case OP_BUMUL_NO_OVFL: + case OP_BUMUL_OVFL: + case OP_ULEQ: + case OP_UGEQ: + case OP_UGT: + case OP_ULT: + case OP_SLEQ: + case OP_SGEQ: + case OP_SGT: + case OP_SLT: + UNREACHABLE(); + break; + default: + UNREACHABLE(); + break; + } + val.clear_overflow_bits(val.bits); + } + + bool sls_eval::try_repair(app* e, unsigned i) { + if (is_fixed0(e->get_arg(i))) + return false; + if (e->get_family_id() == basic_family_id) + return try_repair_basic(e, i); + if (e->get_family_id() == bv.get_family_id()) + return try_repair_bv(e, i); + return false; + } + + bool sls_eval::try_repair_basic(app* e, unsigned i) { + switch (e->get_decl_kind()) { + case OP_AND: + return try_repair_and_or(e, i); + case OP_OR: + return try_repair_and_or(e, i); + case OP_NOT: + return try_repair_not(e); + case OP_FALSE: + return false; + case OP_TRUE: + return false; + case OP_EQ: + return try_repair_eq(e, i); + case OP_IMPLIES: + return try_repair_implies(e, i); + case OP_XOR: + return try_repair_xor(e, i); + case OP_ITE: + return try_repair_ite(e, i); + default: + UNREACHABLE(); + return false; + } + } + + bool sls_eval::try_repair_bv(app* e, unsigned i) { + switch (e->get_decl_kind()) { + case OP_BAND: + return try_repair_band(wval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_BOR: + return try_repair_bor(wval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_BXOR: + return try_repair_bxor(wval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_BADD: + return try_repair_add(wval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_BMUL: + return try_repair_mul(wval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_BNOT: + return try_repair_bnot(wval0(e), wval0(e, i)); + case OP_BNEG: + return try_repair_bneg(wval0(e), wval0(e, i)); + case OP_BIT0: + return false; + case OP_BIT1: + return false; + case OP_BV2INT: + return false; + case OP_INT2BV: + return false; + case OP_ULEQ: + if (i == 0) + return try_repair_ule(bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_uge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_UGEQ: + if (i == 0) + return try_repair_uge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_ule(bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_UGT: + if (i == 0) + return try_repair_ule(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_uge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_ULT: + if (i == 0) + return try_repair_uge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_ule(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_SLEQ: + if (i == 0) + return try_repair_sle(bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_sge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_SGEQ: + if (i == 0) + return try_repair_sge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_sle(bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_SGT: + if (i == 0) + return try_repair_sle(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_sge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_SLT: + if (i == 0) + return try_repair_sge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + else + return try_repair_sle(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_BASHR: + case OP_BLSHR: + case OP_BSHL: + case OP_BCOMP: + case OP_BIT2BOOL: + case OP_BNAND: + case OP_BREDAND: + case OP_BREDOR: + case OP_BSDIV: + case OP_BSDIV_I: + case OP_BSDIV0: + case OP_BUDIV: + case OP_BUDIV_I: + case OP_BUDIV0: + case OP_BUREM: + case OP_BUREM_I: + case OP_BUREM0: + case OP_BSMOD: + case OP_BSMOD_I: + case OP_BSMOD0: + case OP_BXNOR: + case OP_BNEG_OVFL: + case OP_BSADD_OVFL: + case OP_BUADD_OVFL: + case OP_BSDIV_OVFL: + case OP_BSMUL_NO_OVFL: + case OP_BSMUL_NO_UDFL: + case OP_BSMUL_OVFL: + case OP_BUMUL_NO_OVFL: + case OP_BUMUL_OVFL: + default: + return false; + } + } + + bool sls_eval::try_repair_and_or(app* e, unsigned i) { + auto b = bval0(e); + auto child = e->get_arg(i); + if (b == bval0(child)) + return false; + m_eval[child->get_id()] = b; + return true; + } + + bool sls_eval::try_repair_not(app* e) { + auto child = e->get_arg(0); + m_eval[child->get_id()] = !bval0(e); + return true; + } + + bool sls_eval::try_repair_eq(app* e, unsigned i) { + auto child = e->get_arg(i); + auto ev = bval0(e); + if (m.is_bool(child)) { + auto bv = bval0(e->get_arg(1 - i)); + m_eval[child->get_id()] = ev == bv; + return true; + } + else if (bv.is_bv(child)) { + auto & a = wval0(e->get_arg(i)); + auto & b = wval0(e->get_arg(1 - i)); + if (ev) + return a.try_set(b.bits); + else { + // pick random bit to differ + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = a.bits[i]; + unsigned idx = m_rand(a.bw); + a.set(m_tmp, idx, !b.get(b.bits, idx)); + return a.try_set(m_tmp); + } + } + return false; + } + + bool sls_eval::try_repair_xor(app* e, unsigned i) { + bool ev = bval0(e); + bool bv = bval0(e->get_arg(1 - i)); + auto child = e->get_arg(i); + m_eval[child->get_id()] = ev != bv; + return true; + } + + bool sls_eval::try_repair_ite(app* e, unsigned i) { + auto child = e->get_arg(i); + bool c = bval0(e->get_arg(0)); + if (i == 0) { + m_eval[child->get_id()] = !c; + return true; + } + if (c != (i == 1)) + return false; + if (m.is_bool(e)) { + m_eval[child->get_id()] = bval0(e); + return true; + } + if (bv.is_bv(e)) + return wval0(child).try_set(wval0(e).bits); + return false; + } + + bool sls_eval::try_repair_implies(app* e, unsigned i) { + auto child = e->get_arg(i); + bool ev = bval0(e); + bool av = bval0(child); + bool bv = bval0(e->get_arg(1 - i)); + if (i == 0) { + if (ev == (!av || bv)) + return false; + } + else if (ev != (!bv || av)) + return false; + m_eval[child->get_id()] = ev; + return true; + } + + // + // e = a & b + // e[i] = 1 -> a[i] = 1 + // e[i] = 0 & b[i] = 1 -> a[i] = 0 + // + // a := e[i] | (~b[i] & a[i]) + + bool sls_eval::try_repair_band(bvval const& e, bvval& a, bvval const& b) { + for (unsigned i = 0; i < e.nw; ++i) + m_tmp[i] = e.bits[i] | (~b.bits[i] & a.bits[i]); + return a.try_set(m_tmp); + } + + // + // e = a | b + // set a[i] to 1 where b[i] = 0, e[i] = 1 + // set a[i] to 0 where e[i] = 0, a[i] = 1 + // + bool sls_eval::try_repair_bor(bvval const& e, bvval& a, bvval const& b) { + for (unsigned i = 0; i < e.nw; ++i) + m_tmp[i] = e.bits[i] & (a.bits[i] | ~b.bits[i]); + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_bxor(bvval const& e, bvval& a, bvval const& b) { + for (unsigned i = 0; i < e.nw; ++i) + m_tmp[i] = e.bits[i] ^ b.bits[i]; + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_add(bvval const& e, bvval& a, bvval const& b) { + digit_t c; + mpn.sub(e.bits.data(), e.nw, b.bits.data(), e.nw, m_tmp.data(), &c); + return a.try_set(m_tmp); + } + + /** + * e = a*b, then a = e * b^-1 + * 8*e = a*(2b), then a = 4e*b^-1 + */ + bool sls_eval::try_repair_mul(bvval const& e, bvval& a, bvval const& b) { + unsigned parity_e = e.parity(e.bits); + unsigned parity_b = b.parity(b.bits); + if (parity_e < parity_b) + return false; + rational ne, nb; + e.get_value(e.bits, ne); + b.get_value(b.bits, nb); + if (parity_b > 0) + ne /= rational::power_of_two(parity_b); + auto inv_b = nb.pseudo_inverse(b.bw); + rational na = mod(inv_b * ne, rational::power_of_two(a.bw)); + a.set_value(m_tmp, na); + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_bnot(bvval const& e, bvval& a) { + for (unsigned i = 0; i < e.nw; ++i) + m_tmp[i] = ~e.bits[i]; + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { + digit_t c; + mpn.sub(m_zero.data(), e.nw, e.bits.data(), e.nw, m_tmp.data(), &c); + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { + if (e) + return a.try_set(b.bits); + else { + digit_t c; + a.set(m_zero, 0, true); + mpn.add(b.bits.data(), a.nw, m_zero.data(), a.nw, &c, a.nw, m_tmp.data()); + a.set(m_zero, 0, false); + return a.try_set(m_tmp); + } + } + + bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) { + if (e) + return a.try_set(b.bits); + else { + digit_t c; + a.set(m_zero, 0, true); + mpn.sub(b.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp.data(), &c); + a.set(m_zero, 0, false); + return a.try_set(m_tmp); + } + } + + bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { + return false; + } + + bool sls_eval::try_repair_sge(bool e, bvval& a, bvval const& b) { + return false; + } + + void sls_eval::repair_up(expr* e) { + if (!is_app(e)) + return; + if (m.is_bool(e)) + set(e, bval1(to_app(e))); + else if (bv.is_bv(e)) + wval0(e).try_set(wval1(to_app(e))); + } +} diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h new file mode 100644 index 000000000..a09065735 --- /dev/null +++ b/src/ast/sls/bv_sls_eval.h @@ -0,0 +1,134 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls.h + +Abstract: + + A Stochastic Local Search (SLS) engine + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ +#pragma once + +#include "ast/ast.h" +#include "ast/sls/sls_valuation.h" +#include "ast/sls/bv_sls_fixed.h" +#include "ast/bv_decl_plugin.h" + +namespace bv { + + class sls_fixed; + + class sls_eval { + friend class sls_fixed; + ast_manager& m; + bv_util bv; + sls_fixed m_fix; + mpn_manager mpn; + ptr_vector m_todo; + random_gen m_rand; + + scoped_ptr_vector m_values0, m_values1; // expr-id -> bv valuation + bool_vector m_eval; // expr-id -> boolean valuation + bool_vector m_fixed; // expr-id -> is Boolean fixed + + mutable svector m_tmp, m_tmp2, m_zero; + + using bvval = sls_valuation; + + + void init_eval_basic(app* e); + void init_eval_bv(app* e); + + /** + * Register e as a bit-vector. + * Return true if not already registered, false if already registered. + */ + bool add_bit_vector(expr* e); + sls_valuation* alloc_valuation(unsigned bit_width); + + bool bval1_basic(app* e) const; + bool bval1_bv(app* e) const; + + /** + * Repair operations + */ + bool try_repair_basic(app* e, unsigned i); + bool try_repair_bv(app * e, unsigned i); + bool try_repair_and_or(app* e, unsigned i); + bool try_repair_not(app* e); + bool try_repair_eq(app* e, unsigned i); + bool try_repair_xor(app* e, unsigned i); + bool try_repair_ite(app* e, unsigned i); + bool try_repair_implies(app* e, unsigned i); + bool try_repair_band(bvval const& e, bvval& a, bvval const& b); + bool try_repair_bor(bvval const& e, bvval& a, bvval const& b); + bool try_repair_add(bvval const& e, bvval& a, bvval const& b); + bool try_repair_mul(bvval const& e, bvval& a, bvval const& b); + bool try_repair_bxor(bvval const& e, bvval& a, bvval const& b); + bool try_repair_bnot(bvval const& e, bvval& a); + bool try_repair_bneg(bvval const& e, bvval& a); + bool try_repair_ule(bool e, bvval& a, bvval const& b); + bool try_repair_uge(bool e, bvval& a, bvval const& b); + bool try_repair_sle(bool e, bvval& a, bvval const& b); + bool try_repair_sge(bool e, bvval& a, bvval const& b); + + sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); } + + void wval1(app* e, sls_valuation& val) const; + + public: + sls_eval(ast_manager& m); + + void init_eval(expr_ref_vector const& es, std::function const& eval); + + void init_fixed(expr_ref_vector const& es) { m_fix.init(es); } + + ptr_vector& sort_assertions(expr_ref_vector const& es); + + /** + * Retrieve evaluation based on cache. + * bval - Boolean values + * wval - Word (bit-vector) values + */ + + bool bval0(expr* e) const { return m_eval[e->get_id()]; } + + sls_valuation& wval0(expr* e) const { return *m_values0[e->get_id()]; } + + bool is_fixed0(expr* e) const { return m_fixed[e->get_id()]; } + + /** + * Retrieve evaluation based on immediate children. + */ + bool bval1(app* e) const; + + svector& wval1(app* e) const; + + /** + * Override evaluaton. + */ + + void set(expr* e, bool b) { + m_eval[e->get_id()] = b; + } + + + /* + * Try to invert value of child to repair value assignment of parent. + */ + + bool try_repair(app* e, unsigned i); + + /* + * Propagate repair up to parent + */ + void repair_up(expr* e); + }; +} diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp new file mode 100644 index 000000000..4dafb6034 --- /dev/null +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -0,0 +1,386 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls_fixed.cpp + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ + +#include "ast/sls/bv_sls_fixed.h" +#include "ast/sls/bv_sls_eval.h" + +namespace bv { + + sls_fixed::sls_fixed(sls_eval& ev): + ev(ev), + m(ev.m), + bv(ev.bv) + {} + + void sls_fixed::init(expr_ref_vector const& es) { + init_ranges(es); + ev.sort_assertions(es); + for (expr* e : ev.m_todo) { + if (!is_app(e)) + continue; + app* a = to_app(e); + ev.m_fixed.setx(a->get_id(), is_fixed1(a), false); + if (a->get_family_id() == basic_family_id) + init_fixed_basic(a); + else if (a->get_family_id() == bv.get_family_id()) + init_fixed_bv(a); + else + ; + } + ev.m_todo.reset(); + } + + + void sls_fixed::init_ranges(expr_ref_vector const& es) { + for (expr* e : es) { + bool sign = m.is_not(e, e); + if (is_app(e)) + init_range(to_app(e), sign); + } + } + + // s <=s t <=> s + K <= t + K, K = 2^{bw-1} + + void sls_fixed::init_range(app* e, bool sign) { + expr* s, * t, * x, * y; + rational a, b; + auto N = [&](expr* s) { + auto b = bv.get_bv_size(s); + return b > 0 ? rational::power_of_two(b - 1) : rational(0); + }; + if (bv.is_ule(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(x, a, y, b, sign); + } + else if (bv.is_ult(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(y, b, x, a, !sign); + } + else if (bv.is_uge(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(y, b, x, a, sign); + } + else if (bv.is_ugt(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(x, a, y, b, !sign); + } + else if (bv.is_sle(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(x, a + N(s), y, b + N(s), sign); + } + else if (bv.is_slt(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(y, b + N(s), x, a + N(s), !sign); + } + else if (bv.is_sge(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(y, b + N(s), x, a + N(s), sign); + } + else if (bv.is_sgt(e, s, t)) { + get_offset(s, x, a); + get_offset(t, y, b); + init_range(x, a + N(s), y, b + N(s), !sign); + } + } + + // + // x + a <= b <=> x in [-a, b - a + 1[ b != -1 + // a <= x + b <=> x in [a - b, -b[ a != 0 + // x + a <= x + b <=> x in [-a, -b[ a != b + // + // x + a < b <=> ! (b <= x + a) <=> x not in [-b, a - b + 1[ <=> x in [a - b + 1, -b [ b != 0 + // a < x + b <=> ! (x + b <= a) <=> x not in [-a, b - a [ <=> x in [b - a, -a [ a != -1 + // x + a < x + b <=> ! (x + b <= x + a) <=> x in [-a, -b [ a != b + // + void sls_fixed::init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign) { + if (!x && !y) + return; + if (!x) { + // a <= y + b + if (a == 0) + return; + auto& v = wval0(y); + if (!sign) + v.add_range(a - b, -b); + else + v.add_range(-b, a - b); + } + else if (!y) { + if (mod(b + 1, rational::power_of_two(bv.get_bv_size(x))) == 1) + return; + auto& v = wval0(x); + if (!sign) + v.add_range(-a, b - a + 1); + else + v.add_range(b - a + 1, -a); + } + else if (x == y) { + if (a == b) + return; + auto& v = wval0(x); + if (!sign) + v.add_range(-a, -b); + else + v.add_range(-b, -a); + } + } + + void sls_fixed::get_offset(expr* e, expr*& x, rational& offset) { + expr* s, * t; + x = e; + offset = 0; + if (bv.is_bv_add(e, s, t)) { + if (bv.is_numeral(s, offset)) + x = t; + else if (bv.is_numeral(t, offset)) + x = s; + } + else if (bv.is_numeral(e, offset)) + x = nullptr; + } + + sls_valuation& sls_fixed::wval0(expr* e) { + return ev.wval0(e); + } + + void sls_fixed::init_fixed_basic(app* e) { + if (bv.is_bv(e) && m.is_ite(e)) { + auto& val = wval0(e); + auto& val_th = wval0(e->get_arg(1)); + auto& val_el = wval0(e->get_arg(2)); + for (unsigned i = 0; i < val.nw; ++i) + val.fixed[i] = val_el.fixed[i] & val_th.fixed[i] & ~(val_el.bits[i] ^ val_th.bits[i]); + } + } + + void sls_fixed::init_fixed_bv(app* e) { + if (bv.is_bv(e)) + set_fixed_bw(e); + } + + bool sls_fixed::is_fixed1(app* e) const { + if (is_uninterp(e)) + return false; + if (e->get_family_id() == basic_family_id) + return is_fixed1_basic(e); + return all_of(*e, [&](expr* arg) { return ev.is_fixed0(arg); }); + } + + bool sls_fixed::is_fixed1_basic(app* e) const { + switch (e->get_decl_kind()) { + case OP_TRUE: + case OP_FALSE: + return true; + case OP_AND: + return any_of(*e, [&](expr* arg) { return ev.is_fixed0(arg) && !ev.bval0(e); }); + case OP_OR: + return any_of(*e, [&](expr* arg) { return ev.is_fixed0(arg) && ev.bval0(e); }); + default: + return all_of(*e, [&](expr* arg) { return ev.is_fixed0(arg); }); + } + } + + void sls_fixed::set_fixed_bw(app* e) { + SASSERT(bv.is_bv(e)); + SASSERT(e->get_family_id() == bv.get_fid()); + auto& v = ev.wval0(e); + if (all_of(*e, [&](expr* arg) { return ev.is_fixed0(arg); })) { + for (unsigned i = 0; i < v.bw; ++i) + v.set(v.fixed, i, true); + ev.m_fixed.setx(e->get_id(), true, false); + return; + } + switch (e->get_decl_kind()) { + case OP_BAND: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + // (a.fixed & b.fixed) | (a.fixed & ~a.bits) | (b.fixed & ~b.bits) + for (unsigned i = 0; i < a.nw; ++i) + v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & ~a.bits[i]) | (b.fixed[i] & ~b.bits[i]); + break; + } + case OP_BOR: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + // (a.fixed & b.fixed) | (a.fixed & a.bits) | (b.fixed & b.bits) + for (unsigned i = 0; i < a.nw; ++i) + v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & a.bits[i]) | (b.fixed[i] & b.bits[i]); + break; + } + case OP_BNOT: { + auto& a = wval0(e->get_arg(0)); + for (unsigned i = 0; i < a.nw; ++i) + v.fixed[i] = a.fixed[i]; + break; + } + case OP_BADD: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + bool pfixed = true; + for (unsigned i = 0; i < v.bw; ++i) { + if (pfixed && a.get(a.fixed, i) && b.get(b.fixed, i)) + v.set(v.fixed, i, true); + else if (!pfixed && a.get(a.fixed, i) && b.get(b.fixed, i) && + !a.get(a.bits, i) && !b.get(b.bits, i)) { + pfixed = true; + v.set(v.fixed, i, false); + } + else { + pfixed = false; + v.set(v.fixed, i, false); + } + } + break; + } + case OP_BMUL: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + unsigned j = 0, k = 0, zj = 0, zk = 0, hzj = 0, hzk = 0; + // i'th bit depends on bits j + k = i + // if the first j, resp k bits are 0, the bits j + k are 0 + for (; j < v.bw; ++j) + if (!a.get(a.fixed, j)) + break; + for (; k < v.bw; ++k) + if (!b.get(b.fixed, k)) + break; + for (; zj < v.bw; ++zj) + if (!a.get(a.fixed, zj) || a.get(a.bits, zj)) + break; + for (; zk < v.bw; ++zk) + if (!b.get(b.fixed, zk) || b.get(b.bits, zk)) + break; + for (; hzj < v.bw; ++hzj) + if (!a.get(a.fixed, v.bw - hzj - 1) || a.get(a.bits, v.bw - hzj - 1)) + break; + for (; hzk < v.bw; ++hzk) + if (!b.get(b.fixed, v.bw - hzk - 1) || b.get(b.bits, v.bw - hzk - 1)) + break; + + + if (j > 0 && k > 0) { + for (unsigned i = 0; i < std::min(k, j); ++i) + v.set(v.fixed, i, true); + } + // lower zj + jk bits are 0 + if (zk > 0 || zj > 0) { + for (unsigned i = 0; i < zk + zj; ++i) + v.set(v.fixed, i, true); + } + // upper bits are 0, if enough high order bits of a, b are 0. + if (hzj < v.bw && hzk < v.bw && hzj + hzk > v.bw) { + hzj = v.bw - hzj; + hzk = v.bw - hzk; + for (unsigned i = hzj + hzk - 1; i < v.bw; ++i) + v.set(v.fixed, i, true); + } + break; + } + case OP_CONCAT: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + for (unsigned i = 0; i < b.bw; ++i) + v.set(v.fixed, i, b.get(b.fixed, i)); + for (unsigned i = 0; i < a.bw; ++i) + v.set(v.fixed, i + b.bw, a.get(a.fixed, i)); + break; + } + case OP_EXTRACT: { + expr* child; + unsigned lo, hi; + VERIFY(bv.is_extract(e, lo, hi, child)); + auto& a = wval0(child); + for (unsigned i = lo; i <= hi; ++i) + v.set(v.fixed, i - lo, a.get(a.fixed, i)); + break; + } + case OP_BNEG: { + auto& a = wval0(e->get_arg(0)); + bool pfixed = true; + for (unsigned i = 0; i < v.bw; ++i) { + if (pfixed && a.get(a.fixed, i)) + v.set(v.fixed, i, true); + else { + pfixed = false; + v.set(v.fixed, i, false); + } + } + break; + } + case OP_BSHL: { + // determine range of b. + // if b = 0, then inherit fixed from a + // if b >= v.bw then make e fixed to 0 + // if 0 < b < v.bw is known, then inherit shift of fixed values of a + // if 0 < b < v.bw but not known, then inherit run lengths of equal bits of a + // that are fixed. + NOT_IMPLEMENTED_YET(); + break; + } + case OP_BASHR: + case OP_BLSHR: + case OP_INT2BV: + case OP_BCOMP: + case OP_BNAND: + case OP_BREDAND: + case OP_BREDOR: + case OP_BSDIV: + case OP_BSDIV_I: + case OP_BSDIV0: + case OP_BUDIV: + case OP_BUDIV_I: + case OP_BUDIV0: + case OP_BUREM: + case OP_BUREM_I: + case OP_BUREM0: + case OP_BSMOD: + case OP_BSMOD_I: + case OP_BSMOD0: + case OP_BXOR: + case OP_BXNOR: + NOT_IMPLEMENTED_YET(); + break; + case OP_BV_NUM: + case OP_BIT0: + case OP_BIT1: + case OP_BV2INT: + case OP_BNEG_OVFL: + case OP_BSADD_OVFL: + case OP_BUADD_OVFL: + case OP_BSDIV_OVFL: + case OP_BSMUL_NO_OVFL: + case OP_BSMUL_NO_UDFL: + case OP_BSMUL_OVFL: + case OP_BUMUL_NO_OVFL: + case OP_BUMUL_OVFL: + case OP_BIT2BOOL: + case OP_ULEQ: + case OP_UGEQ: + case OP_UGT: + case OP_ULT: + case OP_SLEQ: + case OP_SGEQ: + case OP_SGT: + case OP_SLT: + UNREACHABLE(); + break; + } + } +} diff --git a/src/ast/sls/bv_sls_fixed.h b/src/ast/sls/bv_sls_fixed.h new file mode 100644 index 000000000..2dfedca19 --- /dev/null +++ b/src/ast/sls/bv_sls_fixed.h @@ -0,0 +1,52 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls_fixed.h + +Abstract: + + Initialize fixed information. + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ +#pragma once + +#include "ast/ast.h" +#include "ast/sls/sls_valuation.h" +#include "ast/bv_decl_plugin.h" + +namespace bv { + + class sls_eval; + + class sls_fixed { + sls_eval& ev; + ast_manager& m; + bv_util& bv; + + void init_ranges(expr_ref_vector const& es); + void init_range(app* e, bool sign); + void init_range(expr* x, rational const& a, expr* y, rational const& b, bool sign); + void get_offset(expr* e, expr*& x, rational& offset); + + void init_fixed_basic(app* e); + void init_fixed_bv(app* e); + + bool is_fixed1(app* e) const; + bool is_fixed1_basic(app* e) const; + void set_fixed_bw(app* e); + + sls_valuation& wval0(expr* e); + + public: + sls_fixed(sls_eval& ev); + + void init(expr_ref_vector const& es); + + }; +} diff --git a/src/ast/sls/bv_sls_terms.cpp b/src/ast/sls/bv_sls_terms.cpp new file mode 100644 index 000000000..422b2017e --- /dev/null +++ b/src/ast/sls/bv_sls_terms.cpp @@ -0,0 +1,138 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls.cpp + +Abstract: + + A Stochastic Local Search (SLS) engine + Uses invertibility conditions, + interval annotations + don't care annotations + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ + +#include "ast/sls/bv_sls.h" + +namespace bv { + + sls_terms::sls_terms(ast_manager& m): + m(m), + bv(m), + m_assertions(m), + m_pinned(m), + m_translated(m), + m_terms(m){} + + + void sls_terms::assert_expr(expr* e) { + m_assertions.push_back(ensure_binary(e)); + } + + expr* sls_terms::ensure_binary(expr* e) { + expr* top = e; + m_pinned.push_back(e); + m_todo.push_back(e); + expr_fast_mark1 mark; + for (unsigned i = 0; i < m_todo.size(); ++i) { + expr* e = m_todo[i]; + if (!is_app(e)) + continue; + if (m_translated.get(e->get_id(), nullptr)) + continue; + if (mark.is_marked(e)) + continue; + mark.mark(e); + for (auto arg : *to_app(e)) + m_todo.push_back(arg); + } + std::stable_sort(m_todo.begin(), m_todo.end(), [&](expr* a, expr* b) { return get_depth(a) < get_depth(b); }); + for (expr* e : m_todo) + ensure_binary_core(e); + m_todo.reset(); + return m_translated.get(top->get_id()); + } + + void sls_terms::ensure_binary_core(expr* e) { + app* a = to_app(e); + auto arg = [&](unsigned i) { + return m_translated.get(a->get_arg(i)->get_id()); + }; + unsigned num_args = a->get_num_args(); + expr_ref r(m); +#define FOLD_OP(oper) \ + r = arg(0); \ + for (unsigned i = 1; i < num_args; ++i)\ + r = oper(r, arg(i)); \ + + if (m.is_and(e)) { + FOLD_OP(m.mk_and); + } + else if (m.is_or(e)) { + FOLD_OP(m.mk_or); + } + else if (m.is_xor(e)) { + FOLD_OP(m.mk_xor); + } + else if (bv.is_bv_and(e)) { + FOLD_OP(bv.mk_bv_and); + } + else if (bv.is_bv_or(e)) { + FOLD_OP(bv.mk_bv_or); + } + else if (bv.is_bv_xor(e)) { + FOLD_OP(bv.mk_bv_xor); + } + else if (bv.is_bv_add(e)) { + FOLD_OP(bv.mk_bv_add); + } + else if (bv.is_bv_mul(e)) { + FOLD_OP(bv.mk_bv_mul); + } + else if (bv.is_concat(e)) { + FOLD_OP(bv.mk_concat); + } + else { + for (unsigned i = 0; i < num_args; ++i) + m_todo.push_back(arg(i)); + r = m.mk_app(a->get_decl(), num_args, m_todo.data()); + m_todo.reset(); + } + m_translated.setx(e->get_id(), r); + } + + + void sls_terms::init() { + // populate terms + expr_fast_mark1 mark; + for (expr* e : m_assertions) + m_todo.push_back(e); + while (!m_todo.empty()) { + expr* e = m_todo.back(); + m_todo.pop_back(); + if (mark.is_marked(e) || !is_app(e)) + continue; + mark.mark(e); + m_terms.setx(e->get_id(), to_app(e)); + for (expr* arg : *to_app(e)) + m_todo.push_back(arg); + } + // populate parents + m_parents.reserve(m_terms.size()); + for (expr* e : m_terms) { + if (!e || !is_app(e)) + continue; + for (expr* arg : *to_app(e)) + m_parents[arg->get_id()].push_back(e); + } + for (auto a : m_assertions) + m_assertion_set.insert(a->get_id()); + } + +} diff --git a/src/ast/sls/bv_sls_terms.h b/src/ast/sls/bv_sls_terms.h new file mode 100644 index 000000000..688047846 --- /dev/null +++ b/src/ast/sls/bv_sls_terms.h @@ -0,0 +1,70 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + bv_sls_terms.h + +Abstract: + + A Stochastic Local Search (SLS) engine + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ +#pragma once + +#include "util/lbool.h" +#include "util/params.h" +#include "util/scoped_ptr_vector.h" +#include "util/uint_set.h" +#include "ast/ast.h" +#include "ast/sls/sls_stats.h" +#include "ast/sls/sls_powers.h" +#include "ast/sls/sls_valuation.h" +#include "ast/bv_decl_plugin.h" + +namespace bv { + + class sls_terms { + ast_manager& m; + bv_util bv; + ptr_vector m_todo; + expr_ref_vector m_assertions, m_pinned, m_translated; + app_ref_vector m_terms; + vector> m_parents; + tracked_uint_set m_assertion_set; + + expr* ensure_binary(expr* e); + void ensure_binary_core(expr* e); + + public: + sls_terms(ast_manager& m); + + /** + * Add constraints + */ + void assert_expr(expr* e); + + /** + * Initialize structures: assertions, parents, terms + */ + void init(); + + /** + * Accessors. + */ + + ptr_vector const& parents(expr* e) const { return m_parents[e->get_id()]; } + + expr_ref_vector const& assertions() const { return m_assertions; } + + app* term(unsigned id) const { return m_terms.get(id); } + + bool is_assertion(expr* e) const { return m_assertion_set.contains(e->get_id()); } + + + }; +} diff --git a/src/ast/sls/sls_engine.cpp b/src/ast/sls/sls_engine.cpp index 8bf70f3dd..249c771ed 100644 --- a/src/ast/sls/sls_engine.cpp +++ b/src/ast/sls/sls_engine.cpp @@ -76,19 +76,6 @@ void sls_engine::updt_params(params_ref const & _p) { NOT_IMPLEMENTED_YET(); } -void sls_engine::collect_statistics(statistics& st) const { - double seconds = m_stats.m_stopwatch.get_current_seconds(); - st.update("sls restarts", m_stats.m_restarts); - st.update("sls full evals", m_stats.m_full_evals); - st.update("sls incr evals", m_stats.m_incr_evals); - st.update("sls incr evals/sec", m_stats.m_incr_evals / seconds); - st.update("sls FLIP moves", m_stats.m_flips); - st.update("sls INC moves", m_stats.m_incs); - st.update("sls DEC moves", m_stats.m_decs); - st.update("sls INV moves", m_stats.m_invs); - st.update("sls moves", m_stats.m_moves); - st.update("sls moves/sec", m_stats.m_moves / seconds); -} bool sls_engine::full_eval(model & mdl) { diff --git a/src/ast/sls/sls_engine.h b/src/ast/sls/sls_engine.h index 32338b8ae..614534f1a 100644 --- a/src/ast/sls/sls_engine.h +++ b/src/ast/sls/sls_engine.h @@ -22,42 +22,15 @@ Notes: #include "util/lbool.h" #include "ast/converters/model_converter.h" +#include "ast/sls/sls_stats.h" #include "ast/sls/sls_tracker.h" #include "ast/sls/sls_evaluator.h" -#include "util/statistics.h" class sls_engine { -public: - class stats { - public: - unsigned m_restarts; - stopwatch m_stopwatch; - unsigned m_full_evals; - unsigned m_incr_evals; - unsigned m_moves, m_flips, m_incs, m_decs, m_invs; - - stats() : - m_restarts(0), - m_full_evals(0), - m_incr_evals(0), - m_moves(0), - m_flips(0), - m_incs(0), - m_decs(0), - m_invs(0) { - m_stopwatch.reset(); - m_stopwatch.start(); - } - void reset() { - m_full_evals = m_flips = m_incr_evals = 0; - m_stopwatch.reset(); - m_stopwatch.start(); - } - }; protected: ast_manager & m_manager; - stats m_stats; + bv::sls_stats m_stats; unsynch_mpz_manager m_mpz_manager; powers m_powers; mpz m_zero, m_one, m_two; @@ -94,8 +67,8 @@ public: void assert_expr(expr * e) { m_assertions.push_back(e); } - stats const & get_stats(void) { return m_stats; } - void collect_statistics(statistics & st) const; + bv::sls_stats const & get_stats(void) { return m_stats; } + void collect_statistics(statistics & st) const { m_stats.collect_statistics(st); } void reset_statistics() { m_stats.reset(); } bool full_eval(model & mdl); diff --git a/src/ast/sls/sls_powers.h b/src/ast/sls/sls_powers.h index 9616c43ab..80ccbe04f 100644 --- a/src/ast/sls/sls_powers.h +++ b/src/ast/sls/sls_powers.h @@ -20,6 +20,7 @@ Notes: #pragma once #include "util/mpz.h" +#include "util/map.h" class powers : public u_map { unsynch_mpz_manager & m; diff --git a/src/ast/sls/sls_stats.h b/src/ast/sls/sls_stats.h new file mode 100644 index 000000000..8599a1f64 --- /dev/null +++ b/src/ast/sls/sls_stats.h @@ -0,0 +1,48 @@ +#pragma once +#include "util/statistics.h" +#include "util/stopwatch.h" + + +namespace bv { + class sls_stats { + public: + unsigned m_restarts; + stopwatch m_stopwatch; + unsigned m_full_evals; + unsigned m_incr_evals; + unsigned m_moves, m_flips, m_incs, m_decs, m_invs; + + sls_stats() : + m_restarts(0), + m_full_evals(0), + m_incr_evals(0), + m_moves(0), + m_flips(0), + m_incs(0), + m_decs(0), + m_invs(0) { + m_stopwatch.reset(); + m_stopwatch.start(); + } + void reset() { + m_full_evals = m_flips = m_incr_evals = 0; + m_stopwatch.reset(); + m_stopwatch.start(); + } + + void collect_statistics(statistics& st) const { + double seconds = m_stopwatch.get_current_seconds(); + st.update("sls restarts", m_restarts); + st.update("sls full evals", m_full_evals); + st.update("sls incr evals", m_incr_evals); + st.update("sls incr evals/sec", m_incr_evals / seconds); + st.update("sls FLIP moves", m_flips); + st.update("sls INC moves", m_incs); + st.update("sls DEC moves", m_decs); + st.update("sls INV moves", m_invs); + st.update("sls moves", m_moves); + st.update("sls moves/sec", m_moves / seconds); + } + + }; +} diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp new file mode 100644 index 000000000..bb15c8da3 --- /dev/null +++ b/src/ast/sls/sls_valuation.cpp @@ -0,0 +1,127 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + sls_valuation.cpp + +Abstract: + + A Stochastic Local Search (SLS) engine + Uses invertibility conditions, + interval annotations + don't care annotations + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ + +#include "ast/sls/sls_valuation.h" + +namespace bv { + + sls_valuation::sls_valuation(unsigned bw): bw(bw) { + nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); + unsigned num_bytes = nw * sizeof(digit_t); + lo.reserve(nw); + hi.reserve(nw); + bits.reserve(nw); + fixed.reserve(nw); + // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated + for (unsigned i = 0; i < nw; ++i) + lo[i] = 0, hi[i] = 0, bits[i] = 0, fixed[i] = 0; + for (unsigned i = bw; i < 8 * sizeof(digit_t) * nw; ++i) + set(fixed, i, true); + } + + sls_valuation::~sls_valuation() { + } + + bool sls_valuation::is_feasible() const { + return true; + mpn_manager m; + unsigned nb = (bw + 7) / 8; + auto c = m.compare(lo.data(), nb, hi.data(), nb); + if (c == 0) + return true; + if (c < 0) + return + m.compare(lo.data(), nb, bits.data(), nb) <= 0 && + m.compare(bits.data(), nb, hi.data(), nb) < 0; + return + m.compare(lo.data(), nb, bits.data(), nb) <= 0 || + m.compare(bits.data(), nb, hi.data(), nb) < 0; + } + + bool sls_valuation::eq(sls_valuation const& other) const { + SASSERT(bw == other.bw); + auto c = 0 == memcmp(bits.data(), other.bits.data(), bw / 8); + if (bw % 8 == 0 || !c) + return c; + NOT_IMPLEMENTED_YET(); + return false; + } + + void sls_valuation::clear_overflow_bits(svector& bits) const { + for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) + set(bits, i, false); + } + + void sls_valuation::set_value(svector& bits, rational const& n) { + for (unsigned i = 0; i < bw; ++i) + set(bits, i, n.get_bit(i)); + clear_overflow_bits(bits); + } + + void sls_valuation::get_value(svector const& bits, rational& r) const { + rational p(1); + for (unsigned i = 0; i < nw; ++i) { + r += p * rational(bits[i]); + p *= rational::power_of_two(bw); + } + } + + void sls_valuation::set1(svector& bits) { + for (unsigned i = 0; i < bw; ++i) + set(bits, i, true); + } + + bool sls_valuation::can_set(svector const& new_bits) const { + for (unsigned i = 0; i < nw; ++i) + if (bits[i] != ((new_bits[i] & ~fixed[i]) | (bits[i] & fixed[i]))) + return true; + return false; + } + + unsigned sls_valuation::to_nat(svector const& d, unsigned max_n) { + SASSERT(max_n < UINT_MAX / 2); + unsigned p = 1; + unsigned value = 0; + for (unsigned i = 0; i < bw; ++i) { + if (p >= max_n) { + for (unsigned j = i; j < bw; ++j) + if (get(d, j)) + return max_n; + return value; + } + if (get(d, i)) + value += p; + p <<= 1; + } + return value; + } + + void sls_valuation::add_range(rational l, rational h) { + l = mod(l, rational::power_of_two(bw)); + h = mod(h, rational::power_of_two(bw)); + if (h == l) + return; + set_value(this->lo, l); + set_value(this->hi, h); + // TODO: intersect with previous range, if any + + } + +} diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h new file mode 100644 index 000000000..bdc731bfd --- /dev/null +++ b/src/ast/sls/sls_valuation.h @@ -0,0 +1,116 @@ +/*++ +Copyright (c) 2024 Microsoft Corporation + +Module Name: + + sls_valuation.h + +Abstract: + + A Stochastic Local Search (SLS) engine + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-07 + +--*/ +#pragma once + +#include "util/lbool.h" +#include "util/params.h" +#include "util/scoped_ptr_vector.h" +#include "util/uint_set.h" +#include "ast/ast.h" +#include "ast/sls/sls_stats.h" +#include "ast/sls/sls_powers.h" +#include "ast/bv_decl_plugin.h" + +namespace bv { + + struct sls_valuation { + unsigned bw; // bit-width + unsigned nw; // num words + svector lo, hi; // range assignment to bit-vector, as wrap-around interval + svector bits, fixed; // bit assignment and don't care bit + bool is_feasible() const; // the current bit-evaluation is between lo and hi. + sls_valuation(unsigned bw); + ~sls_valuation(); + + unsigned num_bytes() const { return (bw + 7) / 8; } + + void set_value(svector& bits, rational const& r); + void get_value(svector const& bits, rational& r) const; + void add_range(rational lo, rational hi); + void set1(svector& bits); + + void clear_overflow_bits(svector& bits) const; + bool can_set(svector const& bits) const; + + bool eq(sls_valuation const& other) const; + + bool gt(svector const& a, svector const& b) const { + return 0 > memcmp(a.data(), b.data(), num_bytes()); + } + + unsigned parity(svector const& bits) const { + unsigned i = 0; + for (; i < bw && !get(bits, i); ++i); + return i; + } + + bool try_set(svector const& src) { + if (!can_set(src)) + return false; + set(src); + return true; + } + + void set(svector const& src) { + for (unsigned i = nw; i-- > 0; ) + bits[i] = src[i]; + clear_overflow_bits(bits); + } + + void set_fixed(svector const& src) { + for (unsigned i = nw; i-- > 0; ) + fixed[i] = src[i]; + } + + void set(svector& d, unsigned bit_idx, bool val) const { + auto _val = static_cast(0 - static_cast(val)); + get_bit_word(d, bit_idx) ^= (_val ^ get_bit_word(d, bit_idx)) & get_pos_mask(bit_idx); + } + + bool get(svector const& d, unsigned bit_idx) const { + return (get_bit_word(d, bit_idx) & get_pos_mask(bit_idx)) != 0; + } + + unsigned to_nat(svector const& d, unsigned max_n); + + static digit_t get_pos_mask(unsigned bit_idx) { + return (digit_t)1 << (digit_t)(bit_idx % (8 * sizeof(digit_t))); + } + + static digit_t get_bit_word(svector const& bits, unsigned bit_idx) { + return bits[bit_idx / (8 * sizeof(digit_t))]; + } + + static digit_t& get_bit_word(svector& bits, unsigned bit_idx) { + return bits[bit_idx / (8 * sizeof(digit_t))]; + } + + std::ostream& display(std::ostream& out) const { + out << std::hex; + for (unsigned i = 0; i < nw; ++i) + out << bits[i]; + out << " "; + for (unsigned i = 0; i < nw; ++i) + out << fixed[i]; + out << std::dec; + return out; + } + }; + + inline std::ostream& operator<<(std::ostream& out, sls_valuation const& v) { return v.display(out); } + +} diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index 6daadc83b..ca3f46bc0 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -29,6 +29,7 @@ Notes: #include "tactic/sls/sls_tactic.h" #include "params/sls_params.hpp" #include "ast/sls/sls_engine.h" +#include "ast/sls/bv_sls.h" class sls_tactic : public tactic { ast_manager & m; @@ -123,11 +124,111 @@ public: }; +class bv_sls_tactic : public tactic { + ast_manager& m; + params_ref m_params; + bv::sls* m_engine; + +public: + bv_sls_tactic(ast_manager& _m, params_ref const& p) : + m(_m), + m_params(p) { + m_engine = alloc(bv::sls, m); + } + + tactic* translate(ast_manager& m) override { + return alloc(bv_sls_tactic, m, m_params); + } + + ~bv_sls_tactic() override { + dealloc(m_engine); + } + + char const* name() const override { return "bv-sls"; } + + void updt_params(params_ref const& p) override { + m_params.append(p); + m_engine->updt_params(m_params); + } + + void collect_param_descrs(param_descrs& r) override { + sls_params::collect_param_descrs(r); + } + + void run(goal_ref const& g, model_converter_ref& mc) { + if (g->inconsistent()) { + mc = nullptr; + return; + } + + for (unsigned i = 0; i < g->size(); i++) + m_engine->assert_expr(g->form(i)); + + m_engine->init(); + std::function false_eval = [&](expr* e, unsigned idx) { + return false; + }; + m_engine->init_eval(false_eval); + + lbool res = m_engine->operator()(); + auto const& stats = m_engine->get_stats(); + report_tactic_progress("Number of flips:", stats.m_moves); + IF_VERBOSE(0, verbose_stream() << res << "\n"); + IF_VERBOSE(0, m_engine->display(verbose_stream())); + if (res == l_true) { + + if (g->models_enabled()) { + model_ref mdl = m_engine->get_model(); + mc = model2model_converter(mdl.get()); + TRACE("sls_model", mc->display(tout);); + } + g->reset(); + } + else + mc = nullptr; + + } + + void operator()(goal_ref const& g, + goal_ref_buffer& result) override { + result.reset(); + + TRACE("sls", g->display(tout);); + tactic_report report("sls", *g); + + model_converter_ref mc; + run(g, mc); + g->add(mc.get()); + g->inc_depth(); + result.push_back(g.get()); + } + + void cleanup() override { + auto* d = alloc(bv::sls, m); + std::swap(d, m_engine); + dealloc(d); + } + + void collect_statistics(statistics& st) const override { + m_engine->collect_statistics(st); + } + + void reset_statistics() override { + m_engine->reset_statistics(); + } + +}; + static tactic * mk_sls_tactic(ast_manager & m, params_ref const & p) { return and_then(fail_if_not(mk_is_qfbv_probe()), // Currently only QF_BV is supported. clean(alloc(sls_tactic, m, p))); } +tactic* mk_bv_sls_tactic(ast_manager& m, params_ref const& p) { + return and_then(fail_if_not(mk_is_qfbv_probe()), // Currently only QF_BV is supported. + clean(alloc(bv_sls_tactic, m, p))); +} + static tactic * mk_preamble(ast_manager & m, params_ref const & p) { params_ref main_p; @@ -171,3 +272,9 @@ tactic * mk_qfbv_sls_tactic(ast_manager & m, params_ref const & p) { t->updt_params(p); return t; } + +tactic* mk_qfbv_new_sls_tactic(ast_manager& m, params_ref const& p) { + tactic* t = and_then(mk_preamble(m, p), mk_bv_sls_tactic(m, p)); + t->updt_params(p); + return t; +} diff --git a/src/tactic/sls/sls_tactic.h b/src/tactic/sls/sls_tactic.h index 3c0612e6e..d58d310e3 100644 --- a/src/tactic/sls/sls_tactic.h +++ b/src/tactic/sls/sls_tactic.h @@ -24,7 +24,16 @@ class tactic; tactic * mk_qfbv_sls_tactic(ast_manager & m, params_ref const & p = params_ref()); +tactic* mk_qfbv_new_sls_tactic(ast_manager& m, params_ref const& p = params_ref()); + +tactic* mk_bv_sls_tactic(ast_manager& m, params_ref const& p = params_ref()); + /* ADD_TACTIC("qfbv-sls", "(try to) solve using stochastic local search for QF_BV.", "mk_qfbv_sls_tactic(m, p)") + + ADD_TACTIC("qfbv-new-sls", "(try to) solve using stochastic local search for QF_BV.", "mk_qfbv_new_sls_tactic(m, p)") + + ADD_TACTIC("qfbv-new-sls-core", "(try to) solve using stochastic local search for QF_BV.", "mk_bv_sls_tactic(m, p)") + */ From bd323d6fab6dff09642986bda2aa7b5b495f7dbe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Feb 2024 20:28:18 +0700 Subject: [PATCH 10/69] save --- src/ast/sls/bv_sls.cpp | 6 +++--- src/ast/sls/sls_valuation.cpp | 11 ++++++----- src/ast/sls/sls_valuation.h | 4 +++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 90058607e..33b635376 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -55,6 +55,7 @@ namespace bv { unsigned index = m_rand(m_repair_down.size()); unsigned expr_id = m_repair_down.elem_at(index); auto e = m_terms.term(expr_id); + IF_VERBOSE(20, verbose_stream() << "d " << mk_bounded_pp(e, m, 1) << "\n"); if (eval_is_correct(e)) m_repair_down.remove(expr_id); else @@ -64,6 +65,7 @@ namespace bv { unsigned index = m_rand(m_repair_up.size()); unsigned expr_id = m_repair_up.elem_at(index); auto e = m_terms.term(expr_id); + IF_VERBOSE(20, verbose_stream() << "u " << mk_bounded_pp(e, m, 1) << "\n"); if (eval_is_correct(e)) m_repair_up.remove(expr_id); else @@ -76,7 +78,6 @@ namespace bv { } bool sls::try_repair_down(app* e) { - IF_VERBOSE(20, verbose_stream() << "d " << mk_bounded_pp(e, m, 1) << "\n"); unsigned n = e->get_num_args(); unsigned s = m_rand(n); for (unsigned i = 0; i < n; ++i) @@ -97,7 +98,6 @@ namespace bv { } bool sls::try_repair_up(app* e) { - IF_VERBOSE(20, verbose_stream() << "u " << mk_bounded_pp(e, m, 1) << "\n"); m_repair_up.remove(e->get_id()); if (m_terms.is_assertion(e)) { m_repair_down.insert(e->get_id()); @@ -114,7 +114,7 @@ namespace bv { if (m.is_bool(e)) return m_eval.bval0(e) == m_eval.bval1(e); if (bv.is_bv(e)) - return 0 == memcmp(m_eval.wval0(e).bits.data(), m_eval.wval1(e).data(), m_eval.wval0(e).nw * 8); + return 0 == m_eval.wval0(e).eq(m_eval.wval1(e)); UNREACHABLE(); return false; } diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index bb15c8da3..a45602899 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -55,13 +55,14 @@ namespace bv { m.compare(bits.data(), nb, hi.data(), nb) < 0; } - bool sls_valuation::eq(sls_valuation const& other) const { - SASSERT(bw == other.bw); - auto c = 0 == memcmp(bits.data(), other.bits.data(), bw / 8); + bool sls_valuation::eq(svector const& other) const { + auto c = 0 == memcmp(bits.data(), other.data(), bw / 8); if (bw % 8 == 0 || !c) return c; - NOT_IMPLEMENTED_YET(); - return false; + for (unsigned i = 8 * (bw / 8); i < bw; ++i) + if (get(bits, i) != get(other, i)) + return false; + return true; } void sls_valuation::clear_overflow_bits(svector& bits) const { diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index bdc731bfd..1bf61698c 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -46,7 +46,9 @@ namespace bv { void clear_overflow_bits(svector& bits) const; bool can_set(svector const& bits) const; - bool eq(sls_valuation const& other) const; + bool eq(sls_valuation const& other) const { return eq(other.bits); } + + bool eq(svector const& other) const; bool gt(svector const& a, svector const& b) const { return 0 > memcmp(a.data(), b.data(), num_bytes()); From 1cf008dd0a4433ed14442822bddd1611ddffac07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Feb 2024 16:59:52 +0700 Subject: [PATCH 11/69] updates --- src/ast/sls/bv_sls.cpp | 4 +- src/ast/sls/bv_sls_eval.cpp | 211 +++++++++++++++++++++++++++++++----- src/ast/sls/bv_sls_eval.h | 8 +- src/ast/sls/sls_valuation.h | 29 +++++ 4 files changed, 219 insertions(+), 33 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 33b635376..46b2c2183 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -79,6 +79,8 @@ namespace bv { bool sls::try_repair_down(app* e) { unsigned n = e->get_num_args(); + if (n == 0) + return false; unsigned s = m_rand(n); for (unsigned i = 0; i < n; ++i) if (try_repair_down(e, (i + s) % n)) @@ -114,7 +116,7 @@ namespace bv { if (m.is_bool(e)) return m_eval.bval0(e) == m_eval.bval1(e); if (bv.is_bv(e)) - return 0 == m_eval.wval0(e).eq(m_eval.wval1(e)); + return m_eval.wval0(e).eq(m_eval.wval1(e)); UNREACHABLE(); return false; } diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 990d87dbb..fa4b60538 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -94,6 +94,8 @@ namespace bv { m_tmp2.push_back(0); m_tmp2.push_back(0); m_zero.push_back(0); + m_one.push_back(0); + m_one[0] = 1; } return r; } @@ -207,10 +209,8 @@ namespace bv { for (unsigned i = a.nw; i < 2 * a.nw; ++i) if (m_tmp2[i] != 0) return true; - for (unsigned i = a.bw; i < sizeof(digit_t) * 8 * a.nw; ++i) - if (a.get(m_tmp2, i)) - return true; - return false; + return !a.has_overflow(m_tmp); + return true; }; switch (e->get_decl_kind()) { @@ -247,7 +247,7 @@ namespace bv { auto const& b = wval0(e->get_arg(1)); digit_t c = 0; mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp.data(), a.nw, &c); - return c != 0; + return c != 0 || a.has_overflow(m_tmp); } case OP_BNEG_OVFL: case OP_BSADD_OVFL: @@ -442,23 +442,110 @@ namespace bv { for (unsigned i = 0; i < a.bw; ++i) val.set(val.bits, i, i + sh < a.bw && b.get(b.bits, i + sh)); if (sign) - for (unsigned i = 0; i < sh; ++i) - val.set(val.bits, a.bw - i, true); + val.set_range(val.bits, 0, a.bw - sh, true); } break; } + case OP_SIGN_EXT: { + auto& a = wval0(e->get_arg(0)); + a.set(val.bits); + bool sign = a.get(a.bits, a.bw - 1); + val.set_range(val.bits, a.bw, val.bw, sign); + break; + } + case OP_ZERO_EXT: { + auto& a = wval0(e->get_arg(0)); + a.set(val.bits); + val.set_range(val.bits, a.bw, val.bw, false); + break; + } + case OP_BUREM: + case OP_BUREM_I: + case OP_BUREM0: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + + if (b.is_zero()) + val.set(a.bits); + else { + mpn.div(a.bits.data(), a.nw, + b.bits.data(), b.nw, + m_tmp.data(), // quotient + m_tmp2.data()); // remainder + val.set(m_tmp2); + } + break; + } + case OP_BSMOD: + case OP_BSMOD_I: + case OP_BSMOD0: { + // u = mod(x,y) + // u = 0 -> 0 + // y = 0 -> x + // x < 0, y < 0 -> -u + // x < 0, y >= 0 -> y - u + // x >= 0, y < 0 -> y + u + // x >= 0, y >= 0 -> u + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + if (b.is_zero()) + val.set(a.bits); + else { + digit_t c; + mpn.div(a.bits.data(), a.nw, + b.bits.data(), b.nw, + m_tmp.data(), // quotient + m_tmp2.data()); // remainder + if (val.is_zero(m_tmp2)) + val.set(m_tmp2); + else if (a.sign() && b.sign()) + mpn.sub(m_zero.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), &c), + val.set(m_tmp); + else if (a.sign()) + mpn.sub(b.bits.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), &c), + val.set(m_tmp); + else if (b.sign()) + mpn.add(b.bits.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), a.nw, &c), + val.set(m_tmp); + else + val.set(m_tmp2); + } + break; + } + case OP_BUDIV: + case OP_BUDIV_I: + case OP_BUDIV0: { + // x div 0 = -1 + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + if (b.is_zero()) { + val.set(m_zero); + for (unsigned i = 0; i < a.nw; ++i) + val.bits[i] = ~val.bits[i]; + } + else { + mpn.div(a.bits.data(), a.nw, + b.bits.data(), b.nw, + m_tmp.data(), // quotient + m_tmp2.data()); // remainder + val.set(m_tmp); + } + break; + } + case OP_BSDIV: case OP_BSDIV_I: case OP_BSDIV0: - case OP_BUDIV: - case OP_BUDIV_I: - case OP_BUDIV0: - case OP_BUREM: - case OP_BUREM_I: - case OP_BUREM0: - case OP_BSMOD: - case OP_BSMOD_I: - case OP_BSMOD0: + // d = udiv(abs(x), abs(y)) + // y = 0, x > 0 -> 1 + // y = 0, x <= 0 -> -1 + // x = 0, y != 0 -> 0 + // x > 0, y < 0 -> -d + // x < 0, y > 0 -> -d + // x > 0, y > 0 -> d + // x < 0, y < 0 -> d + + case OP_BREDAND: case OP_BREDOR: case OP_BXNOR: @@ -595,10 +682,18 @@ namespace bv { else return try_repair_sle(!bval0(e), wval0(e, i), wval0(e, 1 - i)); case OP_BASHR: + return try_repair_ashr(wval0(e), wval0(e, 0), wval0(e, 1), i); case OP_BLSHR: + return try_repair_lshr(wval0(e), wval0(e, 0), wval0(e, 1), i); case OP_BSHL: + return try_repair_shl(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BIT2BOOL: { + unsigned idx; + expr* arg; + VERIFY(bv.is_bit2bool(e, arg, idx)); + return try_repair_bit2bool(wval0(e, 0), idx); + } case OP_BCOMP: - case OP_BIT2BOOL: case OP_BNAND: case OP_BREDAND: case OP_BREDOR: @@ -751,15 +846,20 @@ namespace bv { * 8*e = a*(2b), then a = 4e*b^-1 */ bool sls_eval::try_repair_mul(bvval const& e, bvval& a, bvval const& b) { - unsigned parity_e = e.parity(e.bits); - unsigned parity_b = b.parity(b.bits); - if (parity_e < parity_b) + if (b.is_zero()) { + if (a.is_zero()) { + a.set(m_tmp, 1); + return a.try_set(m_tmp); + } return false; + } rational ne, nb; e.get_value(e.bits, ne); b.get_value(b.bits, nb); + unsigned parity_e = e.parity(e.bits); + unsigned parity_b = b.parity(b.bits); if (parity_b > 0) - ne /= rational::power_of_two(parity_b); + ne /= rational::power_of_two(std::min(parity_b, parity_e)); auto inv_b = nb.pseudo_inverse(b.bw); rational na = mod(inv_b * ne, rational::power_of_two(a.bw)); a.set_value(m_tmp, na); @@ -774,7 +874,7 @@ namespace bv { bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { digit_t c; - mpn.sub(m_zero.data(), e.nw, e.bits.data(), e.nw, m_tmp.data(), &c); + mpn.sub(m_zero.data(), e.nw, e.bits.data(), e.nw, m_tmp.data(), &c); return a.try_set(m_tmp); } @@ -782,10 +882,8 @@ namespace bv { if (e) return a.try_set(b.bits); else { - digit_t c; - a.set(m_zero, 0, true); - mpn.add(b.bits.data(), a.nw, m_zero.data(), a.nw, &c, a.nw, m_tmp.data()); - a.set(m_zero, 0, false); + digit_t c; + mpn.add(b.bits.data(), a.nw, m_one.data(), a.nw, &c, a.nw, m_tmp.data()); return a.try_set(m_tmp); } } @@ -795,18 +893,71 @@ namespace bv { return a.try_set(b.bits); else { digit_t c; - a.set(m_zero, 0, true); - mpn.sub(b.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp.data(), &c); - a.set(m_zero, 0, false); + mpn.sub(b.bits.data(), a.nw, m_one.data(), a.nw, m_tmp.data(), &c); return a.try_set(m_tmp); } } bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { - return false; + return try_repair_ule(e, a, b); } bool sls_eval::try_repair_sge(bool e, bvval& a, bvval const& b) { + return try_repair_uge(e, a, b); + } + + bool sls_eval::try_repair_bit2bool(bvval& a, unsigned idx) { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = a.bits[i]; + a.set(m_tmp, idx, !a.get(a.bits, idx)); + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_shl(bvval const& e, bvval& a, bvval& b, unsigned i) { + if (i == 0) { + unsigned sh = b.to_nat(b.bits, b.bw); + if (sh == 0) + return a.try_set(e.bits); + else if (sh >= b.bw) { + return false; + } + else { + // + // e = a << sh + // set bw - sh low order bits to bw - sh high-order of e. + // a[bw - sh - 1: 0] = e[bw - 1: sh] + // a[bw - 1: bw - sh] = unchanged + // + for (unsigned i = 0; i < e.bw - sh; ++i) + e.set(m_tmp, i, e.get(e.bits, sh + i)); + for (unsigned i = e.bw - sh; i < e.bw; ++i) + e.set(m_tmp, i, e.get(a.bits, i)); + return a.try_set(m_tmp); + } + } + else { + SASSERT(i == 1); + } + return false; + } + + bool sls_eval::try_repair_ashr(bvval const& e, bvval & a, bvval& b, unsigned i) { + if (i == 0) { + + } + else { + + } + return false; + } + + bool sls_eval::try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i) { + if (i == 0) { + + } + else { + + } return false; } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index a09065735..85be65377 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -30,7 +30,7 @@ namespace bv { ast_manager& m; bv_util bv; sls_fixed m_fix; - mpn_manager mpn; + mutable mpn_manager mpn; ptr_vector m_todo; random_gen m_rand; @@ -38,7 +38,7 @@ namespace bv { bool_vector m_eval; // expr-id -> boolean valuation bool_vector m_fixed; // expr-id -> is Boolean fixed - mutable svector m_tmp, m_tmp2, m_zero; + mutable svector m_tmp, m_tmp2, m_zero, m_one; using bvval = sls_valuation; @@ -78,6 +78,10 @@ namespace bv { bool try_repair_uge(bool e, bvval& a, bvval const& b); bool try_repair_sle(bool e, bvval& a, bvval const& b); bool try_repair_sge(bool e, bvval& a, bvval const& b); + bool try_repair_shl(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_ashr(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_bit2bool(bvval& a, unsigned idx); sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 1bf61698c..4caf1612a 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -54,6 +54,23 @@ namespace bv { return 0 > memcmp(a.data(), b.data(), num_bytes()); } + bool is_zero() const { return is_zero(bits); } + bool is_zero(svector const& a) const { + for (unsigned i = 0; i < nw; ++i) + if (a[i] != 0) + return false; + return true; + } + + bool sign() const { return get(bits, bw - 1); } + + bool has_overflow(svector const& bits) const { + for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) + if (get(bits, i)) + return true; + return false; + } + unsigned parity(svector const& bits) const { unsigned i = 0; for (; i < bw && !get(bits, i); ++i); @@ -73,16 +90,28 @@ namespace bv { clear_overflow_bits(bits); } + void set_fixed(svector const& src) { for (unsigned i = nw; i-- > 0; ) fixed[i] = src[i]; } + void set_range(svector& dst, unsigned lo, unsigned hi, bool b) { + for (unsigned i = lo; i < hi; ++i) + set(dst, i, b); + } + void set(svector& d, unsigned bit_idx, bool val) const { auto _val = static_cast(0 - static_cast(val)); get_bit_word(d, bit_idx) ^= (_val ^ get_bit_word(d, bit_idx)) & get_pos_mask(bit_idx); } + void set(svector& dst, unsigned v) const { + dst[0] = v; + for (unsigned i = 1; i < nw; ++i) + dst[i] = 0; + } + bool get(svector const& d, unsigned bit_idx) const { return (get_bit_word(d, bit_idx) & get_pos_mask(bit_idx)) != 0; } From ddf2d283508c056d3270d6f50112662fb60f6cac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Feb 2024 09:58:24 +0700 Subject: [PATCH 12/69] add tests for evaluation --- src/ast/sls/bv_sls_eval.cpp | 333 +++++++++++++++++++++++++--------- src/ast/sls/bv_sls_eval.h | 14 +- src/ast/sls/sls_valuation.cpp | 13 +- src/ast/sls/sls_valuation.h | 7 + src/test/CMakeLists.txt | 1 + src/test/main.cpp | 1 + src/test/sls_test.cpp | 203 +++++++++++++++++++++ 7 files changed, 484 insertions(+), 88 deletions(-) create mode 100644 src/test/sls_test.cpp diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index fa4b60538..bb54e0c55 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -89,12 +89,14 @@ namespace bv { sls_valuation* sls_eval::alloc_valuation(unsigned bit_width) { auto* r = alloc(sls_valuation, bit_width); - while (m_tmp.size() < r->nw) { + while (m_tmp.size() < 2 * r->nw) { m_tmp.push_back(0); - m_tmp2.push_back(0); - m_tmp2.push_back(0); + m_tmp2.push_back(0); + m_tmp3.push_back(0); + m_tmp4.push_back(0); m_zero.push_back(0); m_one.push_back(0); + m_minus_one.push_back(~0); m_one[0] = 1; } return r; @@ -195,9 +197,11 @@ namespace bv { auto& b = wval0(e->get_arg(1)); unsigned c; a.set(m_zero, a.bw - 1, true); - mpn.add(a.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp.data(), a.nw, &c); - mpn.add(b.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp2.data(), a.nw, &c); + mpn.add(a.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp.data(), a.nw + 1, &c); + mpn.add(b.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp2.data(), a.nw + 1, &c); a.set(m_zero, a.bw - 1, false); + a.clear_overflow_bits(m_tmp); + a.clear_overflow_bits(m_tmp2); return f(mpn.compare(m_tmp.data(), a.nw, m_tmp2.data(), b.nw)); }; @@ -209,8 +213,7 @@ namespace bv { for (unsigned i = a.nw; i < 2 * a.nw; ++i) if (m_tmp2[i] != 0) return true; - return !a.has_overflow(m_tmp); - return true; + return a.has_overflow(m_tmp2); }; switch (e->get_decl_kind()) { @@ -246,7 +249,7 @@ namespace bv { auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); digit_t c = 0; - mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp.data(), a.nw, &c); + mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp.data(), a.nw + 1, &c); return c != 0 || a.has_overflow(m_tmp); } case OP_BNEG_OVFL: @@ -295,6 +298,63 @@ namespace bv { val.set(wval0(e).bits); return; } + auto set_sdiv = [&]() { + // d = udiv(abs(x), abs(y)) + // y = 0, x > 0 -> -1 + // y = 0, x <= 0 -> -1 + // x = 0, y != 0 -> 0 + // x > 0, y < 0 -> -d + // x < 0, y > 0 -> -d + // x > 0, y > 0 -> d + // x < 0, y < 0 -> d + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + if (a.is_zero() && b.is_zero()) + val.set(m_minus_one); + else if (a.is_zero()) + val.set(m_zero); + else if (b.is_zero()) + val.set(m_minus_one); + else if (!a.sign() && b.is_zero()) + val.set(m_one); + else { + bool sign_a = a.sign(); + bool sign_b = b.sign(); + digit_t c; + + if (sign_a) + mpn.sub(m_zero.data(), a.nw, a.bits.data(), a.nw, m_tmp.data(), &c); + else + a.get(m_tmp); + val.clear_overflow_bits(m_tmp); + + if (sign_b) + mpn.sub(m_zero.data(), a.nw, b.bits.data(), a.nw, m_tmp2.data(), &c); + else + b.get(m_tmp2); + val.clear_overflow_bits(m_tmp2); + + mpn.div(m_tmp.data(), a.nw, m_tmp2.data(), a.nw, m_tmp3.data(), m_tmp4.data()); + if (sign_a == sign_b) + val.set(m_tmp3); + else + mpn.sub(m_zero.data(), a.nw, m_tmp3.data(), a.nw, m_tmp.data(), &c), + val.set(m_tmp); + } + }; + + auto mk_rotate_left = [&](unsigned n) { + auto& a = wval0(e->get_arg(0)); + if (n == 0 || a.bw == 1) + val.set(a.bits); + else { + for (unsigned i = a.bw - n; i < a.bw; ++i) + val.set(val.bits, i + n - a.bw, a.get(a.bits, i)); + for (unsigned i = 0; i < a.bw - n; ++i) + val.set(val.bits, i + a.bw - n, a.get(a.bits, i)); + } + }; + SASSERT(e->get_family_id() == bv.get_fid()); switch (e->get_decl_kind()) { case OP_BV_NUM: { @@ -307,7 +367,7 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - for (unsigned i = 0; i < a.bw; ++i) + for (unsigned i = 0; i < a.nw; ++i) val.bits[i] = a.bits[i] & b.bits[i]; break; } @@ -315,7 +375,7 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - for (unsigned i = 0; i < a.bw; ++i) + for (unsigned i = 0; i < a.nw; ++i) val.bits[i] = a.bits[i] | b.bits[i]; break; } @@ -323,7 +383,7 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - for (unsigned i = 0; i < a.bw; ++i) + for (unsigned i = 0; i < a.nw; ++i) val.bits[i] = a.bits[i] ^ b.bits[i]; break; } @@ -331,7 +391,7 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - for (unsigned i = 0; i < a.bw; ++i) + for (unsigned i = 0; i < a.nw; ++i) val.bits[i] = ~(a.bits[i] & b.bits[i]); break; } @@ -340,7 +400,15 @@ namespace bv { auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); digit_t c; - mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, val.bits.data(), val.nw, &c); + mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, val.bits.data(), val.nw + 1, &c); + break; + } + case OP_BSUB: { + SASSERT(e->get_num_args() == 2); + auto const& a = wval0(e->get_arg(0)); + auto const& b = wval0(e->get_arg(1)); + digit_t c; + mpn.sub(a.bits.data(), a.nw, b.bits.data(), b.nw, val.bits.data(), &c); break; } case OP_BMUL: { @@ -393,17 +461,13 @@ namespace bv { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); auto sh = b.to_nat(b.bits, b.bw); - if (sh == 0) { - for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = a.bits[i]; - } - else if (sh >= b.bw) { - for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = 0; - } + if (sh == 0) + val.set(a.bits); + else if (sh >= b.bw) + val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, i >= sh && b.get(b.bits, i - sh)); + val.set(val.bits, i, i >= sh && a.get(a.bits, i - sh)); } break; } @@ -411,17 +475,13 @@ namespace bv { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); auto sh = b.to_nat(b.bits, b.bw); - if (sh == 0) { - for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = a.bits[i]; - } - else if (sh >= b.bw) { - for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = 0; - } + if (sh == 0) + val.set(a.bits); + else if (sh >= b.bw) + val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, i + sh < a.bw && b.get(b.bits, i + sh)); + val.set(val.bits, i, i + sh < a.bw && a.get(a.bits, i + sh)); } break; } @@ -429,33 +489,31 @@ namespace bv { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); auto sh = b.to_nat(b.bits, b.bw); - auto sign = a.get(a.bits, a.bw - 1); - if (sh == 0) { - for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = a.bits[i]; - } + auto sign = a.sign(); + if (sh == 0) + val.set(a.bits); else if (sh >= b.bw) { for (unsigned i = 0; i < a.nw; ++i) val.bits[i] = sign ? ~0 : 0; } else { - for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, i + sh < a.bw && b.get(b.bits, i + sh)); + for (unsigned i = 0; i < a.bw; ++i) + val.set(val.bits, i, i + sh < a.bw && a.get(a.bits, i + sh)); if (sign) - val.set_range(val.bits, 0, a.bw - sh, true); + val.set_range(val.bits, a.bw - sh, a.bw, true); } break; } case OP_SIGN_EXT: { auto& a = wval0(e->get_arg(0)); - a.set(val.bits); - bool sign = a.get(a.bits, a.bw - 1); + val.set(a.bits); + bool sign = a.sign(); val.set_range(val.bits, a.bw, val.bw, sign); break; } case OP_ZERO_EXT: { auto& a = wval0(e->get_arg(0)); - a.set(val.bits); + val.set(a.bits); val.set_range(val.bits, a.bw, val.bw, false); break; } @@ -505,7 +563,7 @@ namespace bv { mpn.sub(b.bits.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), &c), val.set(m_tmp); else if (b.sign()) - mpn.add(b.bits.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), a.nw, &c), + mpn.add(b.bits.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), a.nw + 1, &c), val.set(m_tmp); else val.set(m_tmp2); @@ -518,11 +576,8 @@ namespace bv { // x div 0 = -1 auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - if (b.is_zero()) { - val.set(m_zero); - for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = ~val.bits[i]; - } + if (b.is_zero()) + val.set(m_minus_one); else { mpn.div(a.bits.data(), a.nw, b.bits.data(), b.nw, @@ -535,17 +590,57 @@ namespace bv { case OP_BSDIV: case OP_BSDIV_I: - case OP_BSDIV0: - // d = udiv(abs(x), abs(y)) - // y = 0, x > 0 -> 1 - // y = 0, x <= 0 -> -1 - // x = 0, y != 0 -> 0 - // x > 0, y < 0 -> -d - // x < 0, y > 0 -> -d - // x > 0, y > 0 -> d - // x < 0, y < 0 -> d - - + case OP_BSDIV0: { + set_sdiv(); + break; + } + case OP_BSREM: + case OP_BSREM0: + case OP_BSREM_I: { + // y = 0 -> x + // else x - sdiv(x, y) * y + // + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + if (b.is_zero()) + val.set(a.bits); + else { + digit_t c; + set_sdiv(); + mpn.mul(val.bits.data(), a.nw, b.bits.data(), a.nw, m_tmp.data()); + mpn.sub(a.bits.data(), a.nw, m_tmp.data(), a.nw, m_tmp2.data(), &c); + val.set(m_tmp2); + } + break; + } + case OP_ROTATE_LEFT: { + unsigned n = e->get_parameter(0).get_int() % val.bw; + mk_rotate_left(n); + break; + } + case OP_ROTATE_RIGHT: { + unsigned n = e->get_parameter(0).get_int() % val.bw; + mk_rotate_left(val.bw - n); + break; + } + case OP_EXT_ROTATE_LEFT: { + auto& b = wval0(e->get_arg(1)); + rational n; + b.get_value(b.bits, n); + n = mod(n, rational(val.bw)); + SASSERT(n.is_unsigned()); + mk_rotate_left(n.get_unsigned()); + break; + } + case OP_EXT_ROTATE_RIGHT: { + auto& b = wval0(e->get_arg(1)); + rational n; + b.get_value(b.bits, n); + n = mod(n, rational(val.bw)); + SASSERT(n.is_unsigned()); + mk_rotate_left(val.bw - n.get_unsigned()); + break; + } case OP_BREDAND: case OP_BREDOR: case OP_BXNOR: @@ -693,22 +788,37 @@ namespace bv { VERIFY(bv.is_bit2bool(e, arg, idx)); return try_repair_bit2bool(wval0(e, 0), idx); } + case OP_BSDIV: + case OP_BSDIV_I: + case OP_BSDIV0: + return try_repair_sdiv(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BUDIV: + case OP_BUDIV_I: + case OP_BUDIV0: + return try_repair_udiv(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BUREM: + case OP_BUREM_I: + case OP_BUREM0: + return try_repair_urem(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BSREM: + case OP_BSREM_I: + case OP_BSREM0: + return try_repair_srem(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BSMOD: + case OP_BSMOD_I: + case OP_BSMOD0: + return try_repair_smod(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_ROTATE_LEFT: + return try_repair_rotate_left(wval0(e), wval0(e, 0), e->get_parameter(0).get_int()); + case OP_ROTATE_RIGHT: + return try_repair_rotate_left(wval0(e), wval0(e, 0), wval0(e).bw - e->get_parameter(0).get_int()); + case OP_EXT_ROTATE_LEFT: + return try_repair_rotate_left(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_EXT_ROTATE_RIGHT: case OP_BCOMP: case OP_BNAND: case OP_BREDAND: case OP_BREDOR: - case OP_BSDIV: - case OP_BSDIV_I: - case OP_BSDIV0: - case OP_BUDIV: - case OP_BUDIV_I: - case OP_BUDIV0: - case OP_BUREM: - case OP_BUREM_I: - case OP_BUREM0: - case OP_BSMOD: - case OP_BSMOD_I: - case OP_BSMOD0: case OP_BXNOR: case OP_BNEG_OVFL: case OP_BSADD_OVFL: @@ -883,7 +993,7 @@ namespace bv { return a.try_set(b.bits); else { digit_t c; - mpn.add(b.bits.data(), a.nw, m_one.data(), a.nw, &c, a.nw, m_tmp.data()); + mpn.add(b.bits.data(), a.nw, m_one.data(), a.nw, &c, a.nw + 1, m_tmp.data()); return a.try_set(m_tmp); } } @@ -918,9 +1028,8 @@ namespace bv { unsigned sh = b.to_nat(b.bits, b.bw); if (sh == 0) return a.try_set(e.bits); - else if (sh >= b.bw) { - return false; - } + else if (sh >= b.bw) + return false; else { // // e = a << sh @@ -936,29 +1045,91 @@ namespace bv { } } else { + // NB. blind sub-range of possible values for b SASSERT(i == 1); + unsigned sh = m_rand(a.bw + 1); + b.set(m_tmp, sh); + return b.try_set(m_tmp); } return false; } bool sls_eval::try_repair_ashr(bvval const& e, bvval & a, bvval& b, unsigned i) { if (i == 0) { - + unsigned sh = b.to_nat(b.bits, b.bw); + if (sh == 0) + return a.try_set(e.bits); + else if (sh >= b.bw) + return false; + else { + // e = a >> sh + // a[bw-1:sh] = e[bw-sh-1:0] + // a[sh-1:0] = a[sh-1:0] + // ignore sign + for (unsigned i = 0; i < a.bw - sh; ++i) + a.set(m_tmp, i + sh, e.get(e.bits, i)); + for (unsigned i = 0; i < sh; ++i) + a.set(m_tmp, i, a.get(a.bits, i)); + return a.try_set(m_tmp); + } } else { - + // NB. blind sub-range of possible values for b + SASSERT(i == 1); + unsigned sh = m_rand(a.bw + 1); + b.set(m_tmp, sh); + return b.try_set(m_tmp); } return false; } bool sls_eval::try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i) { - if (i == 0) { + return try_repair_ashr(e, a, b, i); + } + bool sls_eval::try_repair_sdiv(bvval const& e, bvval& a, bvval& b, unsigned i) { + return false; + } + + bool sls_eval::try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i) { + return false; + } + + bool sls_eval::try_repair_smod(bvval const& e, bvval& a, bvval& b, unsigned i) { + return false; + } + + bool sls_eval::try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i) { + return false; + } + + bool sls_eval::try_repair_srem(bvval const& e, bvval& a, bvval& b, unsigned i) { + return false; + } + + bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) { + // a := rotate_right(e, n) + n = (n % a.bw) - n; + for (unsigned i = a.bw - n; i < a.bw; ++i) + a.set(m_tmp, i + n - a.bw, e.get(e.bits, i)); + for (unsigned i = 0; i < a.bw - n; ++i) + a.set(m_tmp, i + a.bw - n, e.get(e.bits, i)); + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i) { + if (i == 0) { + rational n; + b.get_value(b.bits, n); + n = mod(n, rational(b.bw)); + return try_repair_rotate_left(e, a, n.get_unsigned()); } else { - - } - return false; + SASSERT(i == 1); + unsigned sh = m_rand(b.bw); + b.set(m_tmp, sh); + return b.try_set(m_tmp); + } } void sls_eval::repair_up(expr* e) { diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 85be65377..7d487ea7c 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -27,10 +27,11 @@ namespace bv { class sls_eval { friend class sls_fixed; + friend class sls_test; ast_manager& m; bv_util bv; sls_fixed m_fix; - mutable mpn_manager mpn; + mutable mpn_manager mpn; ptr_vector m_todo; random_gen m_rand; @@ -38,7 +39,7 @@ namespace bv { bool_vector m_eval; // expr-id -> boolean valuation bool_vector m_fixed; // expr-id -> is Boolean fixed - mutable svector m_tmp, m_tmp2, m_zero, m_one; + mutable svector m_tmp, m_tmp2, m_tmp3, m_tmp4, m_zero, m_one, m_minus_one; using bvval = sls_valuation; @@ -82,6 +83,14 @@ namespace bv { bool try_repair_ashr(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_bit2bool(bvval& a, unsigned idx); + bool try_repair_sdiv(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_smod(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_srem(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n); + bool try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i); + sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); } @@ -123,7 +132,6 @@ namespace bv { m_eval[e->get_id()] = b; } - /* * Try to invert value of child to repair value assignment of parent. */ diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index a45602899..e2c58a47c 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -25,10 +25,10 @@ namespace bv { sls_valuation::sls_valuation(unsigned bw): bw(bw) { nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); unsigned num_bytes = nw * sizeof(digit_t); - lo.reserve(nw); - hi.reserve(nw); - bits.reserve(nw); - fixed.reserve(nw); + lo.reserve(nw + 1); + hi.reserve(nw + 1); + bits.reserve(nw + 1); + fixed.reserve(nw + 1); // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated for (unsigned i = 0; i < nw; ++i) lo[i] = 0, hi[i] = 0, bits[i] = 0, fixed[i] = 0; @@ -84,6 +84,11 @@ namespace bv { } } + void sls_valuation::get(svector& dst) const { + for (unsigned i = 0; i < nw; ++i) + dst[i] = bits[i]; + } + void sls_valuation::set1(svector& bits) { for (unsigned i = 0; i < bw; ++i) set(bits, i, true); diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 4caf1612a..60139f53e 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -40,8 +40,10 @@ namespace bv { void set_value(svector& bits, rational const& r); void get_value(svector const& bits, rational& r) const; + void get(svector& dst) const; void add_range(rational lo, rational hi); void set1(svector& bits); + void clear_overflow_bits(svector& bits) const; bool can_set(svector const& bits) const; @@ -90,6 +92,11 @@ namespace bv { clear_overflow_bits(bits); } + void set_zero() { + for (unsigned i = 0; i < nw; ++i) + bits[i] = 0; + } + void set_fixed(svector const& src) { for (unsigned i = nw; i-- > 0; ) diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 14b51f822..4ddc1b8cb 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -108,6 +108,7 @@ add_executable(test-z3 simple_parser.cpp simplex.cpp simplifier.cpp + sls_test.cpp small_object_allocator.cpp smt2print_parse.cpp smt_context.cpp diff --git a/src/test/main.cpp b/src/test/main.cpp index 3f073abf2..0c3d0e01a 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -267,4 +267,5 @@ int main(int argc, char ** argv) { TST(distribution); TST(euf_bv_plugin); TST(euf_arith_plugin); + TST(sls_test); } diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp new file mode 100644 index 000000000..197fa96c9 --- /dev/null +++ b/src/test/sls_test.cpp @@ -0,0 +1,203 @@ + +#include "ast/sls/bv_sls_eval.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/reg_decl_plugins.h" +#include "ast/ast_pp.h" + +namespace bv { + class sls_test { + ast_manager& m; + bv_util bv; + + public: + sls_test(ast_manager& m): + m(m), + bv(m) + {} + + void check_eval(expr* e) { + std::function value = [](expr*, unsigned) { + return false; + }; + expr_ref_vector es(m); + bv_util bv(m); + es.push_back(e); + sls_eval ev(m); + ev.init_eval(es, value); + th_rewriter rw(m); + expr_ref r(e, m); + rw(r); + + if (bv.is_bv(e)) { + auto const& val = ev.wval0(e); + rational n1, n2; + + val.get_value(val.bits, n1); + + VERIFY(bv.is_numeral(r, n2)); + if (n1 != n2) { + verbose_stream() << mk_pp(e, m) << " computed value " << val << "\n"; + verbose_stream() << "should be " << n2 << "\n"; + } + SASSERT(n1 == n2); + VERIFY(n1 == n2); + } + else if (m.is_bool(e)) { + auto val1 = ev.bval0(e); + auto val2 = m.is_true(r) ? true : false; + if (val1 != val2) { + verbose_stream() << mk_pp(e, m) << " computed value " << val1 << " at odds with definition\n"; + } + SASSERT(val1 == val2); + VERIFY(val1 == val2); + } + } + + void check(expr* a, expr* b) { + expr_ref e(m); + auto& validator = *this; + e = bv.mk_bv_add(a, b); + validator.check_eval(e); + + e = bv.mk_bv_mul(a, b); + validator.check_eval(e); + + e = bv.mk_bv_sub(a, b); + validator.check_eval(e); + + e = bv.mk_bv_udiv(a, b); + validator.check_eval(e); + + e = bv.mk_bv_sdiv(a, b); + validator.check_eval(e); + + e = bv.mk_bv_srem(a, b); + validator.check_eval(e); + + e = bv.mk_bv_urem(a, b); + validator.check_eval(e); + + e = bv.mk_bv_smod(a, b); + validator.check_eval(e); + + e = bv.mk_bv_shl(a, b); + validator.check_eval(e); + + e = bv.mk_bv_ashr(a, b); + validator.check_eval(e); + + e = bv.mk_bv_lshr(a, b); + validator.check_eval(e); + + e = bv.mk_bv_and(a, b); + validator.check_eval(e); + + e = bv.mk_bv_or(a, b); + validator.check_eval(e); + + e = bv.mk_bv_xor(a, b); + validator.check_eval(e); + + e = bv.mk_bv_neg(a); + validator.check_eval(e); + + e = bv.mk_bv_not(a); + validator.check_eval(e); + + e = bv.mk_bvumul_ovfl(a, b); + validator.check_eval(e); + + e = bv.mk_bvumul_no_ovfl(a, b); + validator.check_eval(e); + + e = bv.mk_zero_extend(3, a); + validator.check_eval(e); + + e = bv.mk_sign_extend(3, a); + validator.check_eval(e); + + e = bv.mk_ule(a, b); + validator.check_eval(e); + + e = bv.mk_sle(a, b); + validator.check_eval(e); + + e = bv.mk_concat(a, b); + validator.check_eval(e); + + e = bv.mk_extract(6, 3, a); + validator.check_eval(e); + + e = bv.mk_bvuadd_ovfl(a, b); + validator.check_eval(e); + + +#if 0 + + e = bv.mk_bvsadd_ovfl(a, b); + validator.check_eval(e); + + e = bv.mk_bvneg_ovfl(a); + validator.check_eval(e); + + e = bv.mk_bvsmul_no_ovfl(a, b); + validator.check_eval(e); + + e = bv.mk_bvsmul_no_udfl(a, b); + validator.check_eval(e); + + e = bv.mk_bvsmul_ovfl(a, b); + validator.check_eval(e); + + e = bv.mk_bvsdiv_ovfl(a, b); + validator.check_eval(e); + +#endif + +#if 0 + e = bv.mk_rotate_left(a, b); + validator.check_eval(e); + + e = bv.mk_rotate_right(a, b); + validator.check_eval(e); + + e = bv.mk_rotate_left_ext(a, b); + validator.check_eval(e); + + e = bv.mk_rotate_right_ext(a, b); + validator.check_eval(e); + +#endif + } + }; +} + + +static void test_eval1() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + + expr_ref e(m); + + bv::sls_test validator(m); + + unsigned k = 0; + for (unsigned i = 0; i < 256; ++i) { + expr_ref a(bv.mk_numeral(rational(i), 8), m); + for (unsigned j = 0; j < 256; ++j) { + expr_ref b(bv.mk_numeral(rational(j), 8), m); + + ++k; + if (k % 1000 == 0) + verbose_stream() << "tests " << k << "\n"; + + validator.check(a, b); + + } + } +} + +void tst_sls_test() { + test_eval1(); +} From 388b2f5eec9c08155ef0947ca26d53479cd96739 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Feb 2024 14:37:49 +0700 Subject: [PATCH 13/69] n/a --- src/ast/bv_decl_plugin.cpp | 10 ++ src/ast/bv_decl_plugin.h | 5 + src/ast/sls/bv_sls.cpp | 78 ++++++----- src/ast/sls/bv_sls.h | 5 +- src/ast/sls/bv_sls_eval.cpp | 37 ++--- src/ast/sls/bv_sls_eval.h | 3 +- src/ast/sls/sls_valuation.cpp | 72 +++++++--- src/ast/sls/sls_valuation.h | 21 +-- src/test/sls_test.cpp | 245 ++++++++++++++++++---------------- 9 files changed, 274 insertions(+), 202 deletions(-) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 327e280cf..5dd9f6080 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -942,3 +942,13 @@ app* bv_util::mk_int2bv(unsigned sz, expr* e) { parameter p(sz); return m_manager.mk_app(get_fid(), OP_INT2BV, 1, &p, 1, &e); } + +app* bv_util::mk_bv_rotate_left(expr* arg, unsigned n) { + parameter p(n); + return m_manager.mk_app(get_fid(), OP_ROTATE_LEFT, 1, &p, 1, &arg); +} + +app* bv_util::mk_bv_rotate_right(expr* arg, unsigned n) { + parameter p(n); + return m_manager.mk_app(get_fid(), OP_ROTATE_RIGHT, 1, &p, 1, &arg); +} \ No newline at end of file diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 89588ee0e..a2bb9d813 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -546,6 +546,11 @@ public: app * mk_bv2int(expr* e); app * mk_int2bv(unsigned sz, expr* e); + app* mk_bv_rotate_left(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_EXT_ROTATE_LEFT, arg1, arg2); } + app* mk_bv_rotate_right(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_EXT_ROTATE_RIGHT, arg1, arg2); } + app* mk_bv_rotate_left(expr* arg, unsigned n); + app* mk_bv_rotate_right(expr* arg, unsigned n); + // TODO: all these binary ops commute (right?) but it'd be more logical to swap `n` & `m` in the `return` app * mk_bvsmul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_OVFL, n, m); } app * mk_bvsmul_no_udfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_UDFL, n, m); } diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 46b2c2183..6ba3d734e 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -46,46 +46,53 @@ namespace bv { m_eval.init_fixed(m_terms.assertions()); } + std::pair sls::next_to_repair() { + app* e = nullptr; + if (!m_repair_down.empty()) { + unsigned index = m_rand(m_repair_down.size()); + e = m_terms.term(m_repair_down.elem_at(index)); + } + else if (m_repair_up.empty()) { + unsigned index = m_rand(m_repair_up.size()); + e = m_terms.term(m_repair_up.elem_at(index)); + } + return { !m_repair_down.empty(), e }; + } + lbool sls::operator()() { // init and init_eval were invoked. unsigned& n = m_stats.m_moves; n = 0; for (; n < m_config.m_max_repairs && m.inc(); ++n) { - if (!m_repair_down.empty()) { - unsigned index = m_rand(m_repair_down.size()); - unsigned expr_id = m_repair_down.elem_at(index); - auto e = m_terms.term(expr_id); - IF_VERBOSE(20, verbose_stream() << "d " << mk_bounded_pp(e, m, 1) << "\n"); - if (eval_is_correct(e)) - m_repair_down.remove(expr_id); - else - try_repair_down(e); - } - else if (!m_repair_up.empty()) { - unsigned index = m_rand(m_repair_up.size()); - unsigned expr_id = m_repair_up.elem_at(index); - auto e = m_terms.term(expr_id); - IF_VERBOSE(20, verbose_stream() << "u " << mk_bounded_pp(e, m, 1) << "\n"); - if (eval_is_correct(e)) - m_repair_up.remove(expr_id); - else - try_repair_up(e); - } - else + auto [down, e] = next_to_repair(); + if (!e) return l_true; + IF_VERBOSE(20, verbose_stream() << (down?"d ":"u ") << mk_bounded_pp(e, m, 1) << "\n"); + if (eval_is_correct(e)) { + if (down) + m_repair_down.remove(e->get_id()); + else + m_repair_up.remove(e->get_id()); + } + else if (down) { + try_repair_down(e); + } + else + try_repair_up(e); } return l_undef; } - bool sls::try_repair_down(app* e) { + void sls::try_repair_down(app* e) { unsigned n = e->get_num_args(); - if (n == 0) - return false; - unsigned s = m_rand(n); - for (unsigned i = 0; i < n; ++i) - if (try_repair_down(e, (i + s) % n)) - return true; - return false; + if (n > 0) { + unsigned s = m_rand(n); + for (unsigned i = 0; i < n; ++i) + if (try_repair_down(e, (i + s) % n)) + return; + } + m_repair_down.remove(e->get_id()); + m_repair_up.insert(e->get_id()); } bool sls::try_repair_down(app* e, unsigned i) { @@ -99,17 +106,16 @@ namespace bv { return was_repaired; } - bool sls::try_repair_up(app* e) { + void sls::try_repair_up(app* e) { m_repair_up.remove(e->get_id()); if (m_terms.is_assertion(e)) { m_repair_down.insert(e->get_id()); - return false; } - m_eval.repair_up(e); - for (auto p : m_terms.parents(e)) - m_repair_up.insert(p->get_id()); - - return true; + else { + m_eval.repair_up(e); + for (auto p : m_terms.parents(e)) + m_repair_up.insert(p->get_id()); + } } bool sls::eval_is_correct(app* e) { diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index 6acaf483c..781174aee 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -49,10 +49,11 @@ namespace bv { random_gen m_rand; config m_config; + std::pair next_to_repair(); bool eval_is_correct(app* e); - bool try_repair_down(app* e); - bool try_repair_up(app* e); + void try_repair_down(app* e); + void try_repair_up(app* e); bool try_repair_down(app* e, unsigned i); diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index bb54e0c55..630e5e423 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -343,16 +343,9 @@ namespace bv { } }; - auto mk_rotate_left = [&](unsigned n) { + auto mk_rotate_left = [&](unsigned n) { auto& a = wval0(e->get_arg(0)); - if (n == 0 || a.bw == 1) - val.set(a.bits); - else { - for (unsigned i = a.bw - n; i < a.bw; ++i) - val.set(val.bits, i + n - a.bw, a.get(a.bits, i)); - for (unsigned i = 0; i < a.bw - n; ++i) - val.set(val.bits, i + a.bw - n, a.get(a.bits, i)); - } + VERIFY(try_repair_rotate_left(a, val, a.bw - n)); }; SASSERT(e->get_family_id() == bv.get_fid()); @@ -853,6 +846,7 @@ namespace bv { auto child = e->get_arg(i); auto ev = bval0(e); if (m.is_bool(child)) { + SASSERT(!is_fixed0(child)); auto bv = bval0(e->get_arg(1 - i)); m_eval[child->get_id()] = ev == bv; return true; @@ -863,12 +857,21 @@ namespace bv { if (ev) return a.try_set(b.bits); else { - // pick random bit to differ - for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = a.bits[i]; - unsigned idx = m_rand(a.bw); - a.set(m_tmp, idx, !b.get(b.bits, idx)); - return a.try_set(m_tmp); + // pick random bit to differ + a.get(m_tmp); + unsigned start = m_rand(a.bw); + for (unsigned idx = 0; idx < a.bw; ++idx) { + unsigned j = (idx + start) % a.bw; + if (!a.get(a.fixed, j)) { + a.set(m_tmp, idx, !b.get(b.bits, j)); + bool r = a.try_set(m_tmp); + if (r) + return true; + a.set(m_tmp, j, b.get(b.bits, j)); + } + } + // could be due to bounds? + return false; } } return false; @@ -1107,9 +1110,9 @@ namespace bv { return false; } - bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) { + bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const { // a := rotate_right(e, n) - n = (n % a.bw) - n; + n = (a.bw - n) % a.bw; for (unsigned i = a.bw - n; i < a.bw; ++i) a.set(m_tmp, i + n - a.bw, e.get(e.bits, i)); for (unsigned i = 0; i < a.bw - n; ++i) diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 7d487ea7c..5fa51ed17 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -88,10 +88,9 @@ namespace bv { bool try_repair_smod(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_srem(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n); + bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const; bool try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i); - sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); } void wval1(app* e, sls_valuation& val) const; diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index e2c58a47c..fb2c8f129 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -33,26 +33,27 @@ namespace bv { for (unsigned i = 0; i < nw; ++i) lo[i] = 0, hi[i] = 0, bits[i] = 0, fixed[i] = 0; for (unsigned i = bw; i < 8 * sizeof(digit_t) * nw; ++i) - set(fixed, i, true); + set(fixed, i, false); } sls_valuation::~sls_valuation() { } - bool sls_valuation::is_feasible() const { - return true; - mpn_manager m; - unsigned nb = (bw + 7) / 8; - auto c = m.compare(lo.data(), nb, hi.data(), nb); + bool sls_valuation::in_range(svector const& bits) const { + mpn_manager m; + auto c = m.compare(lo.data(), nw, hi.data(), nw); + // full range if (c == 0) return true; + // lo < hi: then lo <= bits & bits < hi if (c < 0) - return - m.compare(lo.data(), nb, bits.data(), nb) <= 0 && - m.compare(bits.data(), nb, hi.data(), nb) < 0; - return - m.compare(lo.data(), nb, bits.data(), nb) <= 0 || - m.compare(bits.data(), nb, hi.data(), nb) < 0; + return + m.compare(lo.data(), nw, bits.data(), nw) <= 0 && + m.compare(bits.data(), nw, hi.data(), nw) < 0; + // hi < lo: bits < hi or lo <= bits + return + m.compare(lo.data(), nw, bits.data(), nw) <= 0 || + m.compare(bits.data(), nw, hi.data(), nw) < 0; } bool sls_valuation::eq(svector const& other) const { @@ -65,11 +66,34 @@ namespace bv { return true; } + bool sls_valuation::gt(svector const& a, svector const& b) const { + mpn_manager m; + return m.compare(a.data(), nw, b.data(), nw) > 0; + } + void sls_valuation::clear_overflow_bits(svector& bits) const { for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) set(bits, i, false); } + bool sls_valuation::get_below(svector const& src, svector& dst) { + for (unsigned i = 0; i < nw; ++i) + dst[i] = (src[i] & ~fixed[i]) | (fixed[i] & bits[i]); + for (unsigned i = 0; i < nw; ++i) + dst[i] = fixed[i] & bits[i]; + if (gt(dst, src)) + return false; + if (!in_range(dst)) { + // lo < hi: + // set dst to lo, except for fixed bits + // + if (gt(hi, lo)) { + + } + } + return true; + } + void sls_valuation::set_value(svector& bits, rational const& n) { for (unsigned i = 0; i < bw; ++i) set(bits, i, n.get_bit(i)); @@ -94,11 +118,16 @@ namespace bv { set(bits, i, true); } - bool sls_valuation::can_set(svector const& new_bits) const { + // + // new_bits != bits => ~fixed + // 0 = (new_bits ^ bits) & fixed + // also check that new_bits are in range + // + bool sls_valuation::can_set(svector const& new_bits) const { for (unsigned i = 0; i < nw; ++i) - if (bits[i] != ((new_bits[i] & ~fixed[i]) | (bits[i] & fixed[i]))) - return true; - return false; + if (0 != ((new_bits[i] ^ bits[i]) & fixed[i])) + return false; + return in_range(new_bits); } unsigned sls_valuation::to_nat(svector const& d, unsigned max_n) { @@ -124,10 +153,15 @@ namespace bv { h = mod(h, rational::power_of_two(bw)); if (h == l) return; - set_value(this->lo, l); - set_value(this->hi, h); + if (eq(lo, hi)) { + set_value(lo, l); + set_value(hi, h); + return; + } + // TODO: intersect with previous range, if any - + set_value(lo, l); + set_value(hi, h); } } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 60139f53e..34ab55f61 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -28,11 +28,10 @@ Author: namespace bv { struct sls_valuation { - unsigned bw; // bit-width - unsigned nw; // num words - svector lo, hi; // range assignment to bit-vector, as wrap-around interval + unsigned bw; // bit-width + unsigned nw; // num words + svector lo, hi; // range assignment to bit-vector, as wrap-around interval svector bits, fixed; // bit assignment and don't care bit - bool is_feasible() const; // the current bit-evaluation is between lo and hi. sls_valuation(unsigned bw); ~sls_valuation(); @@ -44,17 +43,15 @@ namespace bv { void add_range(rational lo, rational hi); void set1(svector& bits); - void clear_overflow_bits(svector& bits) const; + bool in_range(svector const& bits) const; bool can_set(svector const& bits) const; bool eq(sls_valuation const& other) const { return eq(other.bits); } - bool eq(svector const& other) const; - - bool gt(svector const& a, svector const& b) const { - return 0 > memcmp(a.data(), b.data(), num_bytes()); - } + bool eq(svector const& other) const { return eq(other, bits); } + bool eq(svector const& a, svector const& b) const; + bool gt(svector const& a, svector const& b) const; bool is_zero() const { return is_zero(bits); } bool is_zero(svector const& a) const { @@ -79,6 +76,10 @@ namespace bv { return i; } + // retrieve number at or below src which is feasible + // with respect to fixed, lo, hi. + bool get_below(svector const& src, svector& dst); + bool try_set(svector const& src) { if (!can_set(src)) return false; diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp index 197fa96c9..8e9cc10ad 100644 --- a/src/test/sls_test.cpp +++ b/src/test/sls_test.cpp @@ -15,6 +15,12 @@ namespace bv { bv(m) {} + void check_eval(expr* a, expr* b, unsigned j) { + auto es = create_exprs(a, b, j); + for (expr* e : es) + check_eval(e); + } + void check_eval(expr* e) { std::function value = [](expr*, unsigned) { return false; @@ -44,7 +50,7 @@ namespace bv { } else if (m.is_bool(e)) { auto val1 = ev.bval0(e); - auto val2 = m.is_true(r) ? true : false; + auto val2 = m.is_true(r); if (val1 != val2) { verbose_stream() << mk_pp(e, m) << " computed value " << val1 << " at odds with definition\n"; } @@ -53,121 +59,109 @@ namespace bv { } } - void check(expr* a, expr* b) { - expr_ref e(m); - auto& validator = *this; - e = bv.mk_bv_add(a, b); - validator.check_eval(e); - - e = bv.mk_bv_mul(a, b); - validator.check_eval(e); - - e = bv.mk_bv_sub(a, b); - validator.check_eval(e); - - e = bv.mk_bv_udiv(a, b); - validator.check_eval(e); - - e = bv.mk_bv_sdiv(a, b); - validator.check_eval(e); - - e = bv.mk_bv_srem(a, b); - validator.check_eval(e); - - e = bv.mk_bv_urem(a, b); - validator.check_eval(e); - - e = bv.mk_bv_smod(a, b); - validator.check_eval(e); - - e = bv.mk_bv_shl(a, b); - validator.check_eval(e); - - e = bv.mk_bv_ashr(a, b); - validator.check_eval(e); - - e = bv.mk_bv_lshr(a, b); - validator.check_eval(e); - - e = bv.mk_bv_and(a, b); - validator.check_eval(e); - - e = bv.mk_bv_or(a, b); - validator.check_eval(e); - - e = bv.mk_bv_xor(a, b); - validator.check_eval(e); - - e = bv.mk_bv_neg(a); - validator.check_eval(e); - - e = bv.mk_bv_not(a); - validator.check_eval(e); - - e = bv.mk_bvumul_ovfl(a, b); - validator.check_eval(e); - - e = bv.mk_bvumul_no_ovfl(a, b); - validator.check_eval(e); - - e = bv.mk_zero_extend(3, a); - validator.check_eval(e); - - e = bv.mk_sign_extend(3, a); - validator.check_eval(e); - - e = bv.mk_ule(a, b); - validator.check_eval(e); - - e = bv.mk_sle(a, b); - validator.check_eval(e); - - e = bv.mk_concat(a, b); - validator.check_eval(e); - - e = bv.mk_extract(6, 3, a); - validator.check_eval(e); - - e = bv.mk_bvuadd_ovfl(a, b); - validator.check_eval(e); + expr_ref_vector create_exprs(expr* a, expr* b, unsigned j) { + expr_ref_vector result(m); + result.push_back(bv.mk_bv_add(a, b)) + .push_back(bv.mk_bv_mul(a, b)) + .push_back(bv.mk_bv_sub(a, b)) + .push_back(bv.mk_bv_udiv(a, b)) + .push_back(bv.mk_bv_sdiv(a, b)) + .push_back(bv.mk_bv_srem(a, b)) + .push_back(bv.mk_bv_urem(a, b)) + .push_back(bv.mk_bv_smod(a, b)) + .push_back(bv.mk_bv_shl(a, b)) + .push_back(bv.mk_bv_ashr(a, b)) + .push_back(bv.mk_bv_lshr(a, b)) + .push_back(bv.mk_bv_and(a, b)) + .push_back(bv.mk_bv_or(a, b)) + .push_back(bv.mk_bv_xor(a, b)) + .push_back(bv.mk_bv_neg(a)) + .push_back(bv.mk_bv_not(a)) + .push_back(bv.mk_bvumul_ovfl(a, b)) + .push_back(bv.mk_bvumul_no_ovfl(a, b)) + .push_back(bv.mk_zero_extend(3, a)) + .push_back(bv.mk_sign_extend(3, a)) + .push_back(bv.mk_ule(a, b)) + .push_back(bv.mk_sle(a, b)) + .push_back(bv.mk_concat(a, b)) + .push_back(bv.mk_extract(6, 3, a)) + .push_back(bv.mk_bvuadd_ovfl(a, b)) + .push_back(bv.mk_bv_rotate_left(a, j)) + .push_back(bv.mk_bv_rotate_right(a, j)) + .push_back(bv.mk_bv_rotate_left(a, b)) + .push_back(bv.mk_bv_rotate_right(a, b)) + // .push_back(bv.mk_bvsadd_ovfl(a, b)) + // .push_back(bv.mk_bvneg_ovfl(a)) + // .push_back(bv.mk_bvsmul_no_ovfl(a, b)) + // .push_back(bv.mk_bvsmul_no_udfl(a, b)) + // .push_back(bv.mk_bvsmul_ovfl(a, b)) + // .push_back(bv.mk_bvsdiv_ovfl(a, b)) + ; + } -#if 0 + // e = op(a, b), + // update value of a to "random" + // repair a based on computed values. + void check_repair(expr* a, expr* b, unsigned j) { + expr_ref x(m.mk_const("x", bv.mk_sort(bv.get_bv_size(a))), m); + expr_ref y(m.mk_const("y", bv.mk_sort(bv.get_bv_size(b))), m); + auto es1 = create_exprs(a, b, j); + auto es2 = create_exprs(x, b, j); + auto es3 = create_exprs(a, y, j); + for (unsigned i = 0; i < es1.size(); ++i) { + auto e1 = es1.get(i); + auto e2 = es2.get(i); + auto e3 = es3.get(i); + check_repair_idx(e1, e2, 0, x); + if (is_app(e1) && to_app(e1)->get_num_args() == 2) + check_repair_idx(e1, e3, 1, y); + } + } - e = bv.mk_bvsadd_ovfl(a, b); - validator.check_eval(e); + random_gen rand; - e = bv.mk_bvneg_ovfl(a); - validator.check_eval(e); + void check_repair_idx(expr* e1, expr* e2, unsigned idx, expr* x) { + std::function value = [&](expr*, unsigned) { + return rand() % 2 == 0; + }; + expr_ref_vector es(m); + bv_util bv(m); + es.push_back(e1); + es.push_back(e2); + sls_eval ev(m); + ev.init_eval(es, value); + th_rewriter rw(m); + expr_ref r(e1, m); + if (m.is_bool(e1)) { + auto val = m.is_true(r); + auto val2 = ev.bval0(e2); + if (val != val2) { + ev.set(e2, val); + auto rep1 = ev.try_repair(to_app(e2), idx); + if (!rep1) { + verbose_stream() << "Not repaired " << mk_pp(e2, m) << "\n"; + } + SASSERT(rep1); + } + } + if (bv.is_bv(e1)) { + auto& val1 = ev.wval0(e1); + auto& val2 = ev.wval0(e2); + if (!val1.eq(val2)) { + val2.set(val1.bits); + auto rep2 = ev.try_repair(to_app(e2), idx); + if (!rep2) { + verbose_stream() << "Not repaired " << mk_pp(e2, m) << "\n"; + } + SASSERT(rep2); + } + } + } - e = bv.mk_bvsmul_no_ovfl(a, b); - validator.check_eval(e); + // todo: + void test_fixed() { - e = bv.mk_bvsmul_no_udfl(a, b); - validator.check_eval(e); - - e = bv.mk_bvsmul_ovfl(a, b); - validator.check_eval(e); - - e = bv.mk_bvsdiv_ovfl(a, b); - validator.check_eval(e); - -#endif - -#if 0 - e = bv.mk_rotate_left(a, b); - validator.check_eval(e); - - e = bv.mk_rotate_right(a, b); - validator.check_eval(e); - - e = bv.mk_rotate_left_ext(a, b); - validator.check_eval(e); - - e = bv.mk_rotate_right_ext(a, b); - validator.check_eval(e); - -#endif } }; } @@ -183,17 +177,36 @@ static void test_eval1() { bv::sls_test validator(m); unsigned k = 0; - for (unsigned i = 0; i < 256; ++i) { - expr_ref a(bv.mk_numeral(rational(i), 8), m); - for (unsigned j = 0; j < 256; ++j) { - expr_ref b(bv.mk_numeral(rational(j), 8), m); - + unsigned bw = 6; + for (unsigned i = 0; i < 1ul << bw; ++i) { + expr_ref a(bv.mk_numeral(rational(i), bw), m); + for (unsigned j = 0; j < 1ul << bw; ++j) { + expr_ref b(bv.mk_numeral(rational(j), bw), m); ++k; if (k % 1000 == 0) verbose_stream() << "tests " << k << "\n"; + validator.check_eval(a, b, j); + } + } +} - validator.check(a, b); +static void test_repair1() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + expr_ref e(m); + bv::sls_test validator(m); + unsigned k = 0; + unsigned bw = 6; + for (unsigned i = 0; i < 1ul << bw; ++i) { + expr_ref a(bv.mk_numeral(rational(i), bw), m); + for (unsigned j = 0; j < 1ul << bw; ++j) { + expr_ref b(bv.mk_numeral(rational(j), bw), m); + ++k; + if (k % 1000 == 0) + verbose_stream() << "tests " << k << "\n"; + validator.check_repair(a, b, j); } } } From 046db662f9ccb1706bae4180931e482f8b9aa879 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Feb 2024 00:05:37 +0700 Subject: [PATCH 14/69] na --- src/ast/bv_decl_plugin.h | 5 + src/ast/sls/bv_sls_eval.cpp | 375 +++++++++++++++++++++++----------- src/ast/sls/bv_sls_eval.h | 12 +- src/ast/sls/bv_sls_fixed.cpp | 32 ++- src/ast/sls/bv_sls_terms.cpp | 64 ++++++ src/ast/sls/bv_sls_terms.h | 5 +- src/ast/sls/sls_valuation.cpp | 322 ++++++++++++++++++++++++++--- src/ast/sls/sls_valuation.h | 70 ++++++- src/test/sls_test.cpp | 3 +- 9 files changed, 722 insertions(+), 166 deletions(-) diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index a2bb9d813..41c2ef752 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -445,6 +445,11 @@ public: MATCH_BINARY(is_bv_sdivi); MATCH_BINARY(is_bv_udivi); MATCH_BINARY(is_bv_smodi); + MATCH_BINARY(is_bv_urem0); + MATCH_BINARY(is_bv_srem0); + MATCH_BINARY(is_bv_sdiv0); + MATCH_BINARY(is_bv_udiv0); + MATCH_BINARY(is_bv_smod0); MATCH_UNARY(is_bit2bool); MATCH_UNARY(is_int2bv); bool is_bit2bool(expr* e, expr*& bv, unsigned& idx) const; diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 630e5e423..576c0a89e 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -195,13 +195,8 @@ namespace bv { auto scompare = [&](std::function const& f) { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - unsigned c; - a.set(m_zero, a.bw - 1, true); - mpn.add(a.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp.data(), a.nw + 1, &c); - mpn.add(b.bits.data(), a.nw, m_zero.data(), a.nw, m_tmp2.data(), a.nw + 1, &c); - a.set(m_zero, a.bw - 1, false); - a.clear_overflow_bits(m_tmp); - a.clear_overflow_bits(m_tmp2); + add_p2_1(a, m_tmp); + add_p2_1(b, m_tmp2); return f(mpn.compare(m_tmp.data(), a.nw, m_tmp2.data(), b.nw)); }; @@ -209,11 +204,7 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - mpn.mul(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp2.data()); - for (unsigned i = a.nw; i < 2 * a.nw; ++i) - if (m_tmp2[i] != 0) - return true; - return a.has_overflow(m_tmp2); + return a.set_mul(m_tmp2, a.bits, b.bits); }; switch (e->get_decl_kind()) { @@ -248,9 +239,7 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - digit_t c = 0; - mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp.data(), a.nw + 1, &c); - return c != 0 || a.has_overflow(m_tmp); + return a.set_add(m_tmp, a.bits, b.bits); } case OP_BNEG_OVFL: case OP_BSADD_OVFL: @@ -300,8 +289,8 @@ namespace bv { } auto set_sdiv = [&]() { // d = udiv(abs(x), abs(y)) - // y = 0, x > 0 -> -1 - // y = 0, x <= 0 -> -1 + // y = 0, x >= 0 -> -1 + // y = 0, x < 0 -> 1 // x = 0, y != 0 -> 0 // x > 0, y < 0 -> -d // x < 0, y > 0 -> -d @@ -309,39 +298,34 @@ namespace bv { // x < 0, y < 0 -> d auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - if (a.is_zero() && b.is_zero()) - val.set(m_minus_one); + bool sign_a = a.sign(); + bool sign_b = b.sign(); + if (b.is_zero()) { + if (sign_a) + val.set(m_one); + else + val.set(m_minus_one); + } else if (a.is_zero()) val.set(m_zero); - else if (b.is_zero()) - val.set(m_minus_one); - else if (!a.sign() && b.is_zero()) - val.set(m_one); else { - bool sign_a = a.sign(); - bool sign_b = b.sign(); - digit_t c; - if (sign_a) - mpn.sub(m_zero.data(), a.nw, a.bits.data(), a.nw, m_tmp.data(), &c); + a.set_sub(m_tmp, m_zero, a.bits); else a.get(m_tmp); - val.clear_overflow_bits(m_tmp); if (sign_b) - mpn.sub(m_zero.data(), a.nw, b.bits.data(), a.nw, m_tmp2.data(), &c); + b.set_sub(m_tmp2, m_zero, b.bits); else b.get(m_tmp2); - val.clear_overflow_bits(m_tmp2); mpn.div(m_tmp.data(), a.nw, m_tmp2.data(), a.nw, m_tmp3.data(), m_tmp4.data()); if (sign_a == sign_b) val.set(m_tmp3); else - mpn.sub(m_zero.data(), a.nw, m_tmp3.data(), a.nw, m_tmp.data(), &c), - val.set(m_tmp); + val.set_sub(val.bits, m_zero, m_tmp3); } - }; + }; auto mk_rotate_left = [&](unsigned n) { auto& a = wval0(e->get_arg(0)); @@ -392,23 +376,21 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - digit_t c; - mpn.add(a.bits.data(), a.nw, b.bits.data(), b.nw, val.bits.data(), val.nw + 1, &c); + val.set_add(val.bits, a.bits, b.bits); break; } case OP_BSUB: { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - digit_t c; - mpn.sub(a.bits.data(), a.nw, b.bits.data(), b.nw, val.bits.data(), &c); + val.set_sub(val.bits, a.bits, b.bits); break; } case OP_BMUL: { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - mpn.mul(a.bits.data(), a.nw, b.bits.data(), b.nw, m_tmp2.data()); + val.set_mul(m_tmp2, a.bits, b.bits); val.set(m_tmp2); break; } @@ -429,7 +411,7 @@ namespace bv { auto const& a = wval0(child); SASSERT(lo <= hi && hi + 1 <= a.bw && hi - lo + 1 == val.bw); for (unsigned i = lo; i <= hi; ++i) - val.set(val.bits, i - lo, a.get(a.bits, i)); + val.set(val.bits, i - lo, a.get(a.bits, i)); break; } case OP_BNOT: { @@ -440,8 +422,7 @@ namespace bv { } case OP_BNEG: { auto& a = wval0(e->get_arg(0)); - digit_t c; - mpn.sub(m_zero.data(), a.nw, a.bits.data(), a.nw, val.bits.data(), &c); + val.set_sub(val.bits, m_zero, a.bits); break; } case OP_BIT0: @@ -530,7 +511,7 @@ namespace bv { case OP_BSMOD: case OP_BSMOD_I: case OP_BSMOD0: { - // u = mod(x,y) + // u = mod(abs(x),abs(y)) // u = 0 -> 0 // y = 0 -> x // x < 0, y < 0 -> -u @@ -542,22 +523,26 @@ namespace bv { if (b.is_zero()) val.set(a.bits); else { - digit_t c; - mpn.div(a.bits.data(), a.nw, - b.bits.data(), b.nw, + if (a.sign()) + a.set_sub(m_tmp3, m_zero, a.bits); + else + a.set(m_tmp3, a.bits); + if (b.sign()) + b.set_sub(m_tmp4, m_zero, b.bits); + else + a.set(m_tmp4, b.bits); + mpn.div(m_tmp3.data(), a.nw, + m_tmp4.data(), b.nw, m_tmp.data(), // quotient m_tmp2.data()); // remainder if (val.is_zero(m_tmp2)) val.set(m_tmp2); else if (a.sign() && b.sign()) - mpn.sub(m_zero.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), &c), - val.set(m_tmp); + val.set_sub(val.bits, m_zero, m_tmp2); else if (a.sign()) - mpn.sub(b.bits.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), &c), - val.set(m_tmp); + val.set_sub(val.bits, b.bits, m_tmp2); else if (b.sign()) - mpn.add(b.bits.data(), a.nw, m_tmp2.data(), a.nw, m_tmp.data(), a.nw + 1, &c), - val.set(m_tmp); + val.set_add(val.bits, b.bits, m_tmp2); else val.set(m_tmp2); } @@ -590,19 +575,17 @@ namespace bv { case OP_BSREM: case OP_BSREM0: case OP_BSREM_I: { - // y = 0 -> x - // else x - sdiv(x, y) * y + // b = 0 -> a + // else a - sdiv(a, b) * b // auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); if (b.is_zero()) val.set(a.bits); else { - digit_t c; set_sdiv(); - mpn.mul(val.bits.data(), a.nw, b.bits.data(), a.nw, m_tmp.data()); - mpn.sub(a.bits.data(), a.nw, m_tmp.data(), a.nw, m_tmp2.data(), &c); - val.set(m_tmp2); + val.set_mul(m_tmp, val.bits, b.bits); + val.set_sub(val.bits, a.bits, m_tmp); } break; } @@ -669,6 +652,13 @@ namespace bv { val.clear_overflow_bits(val.bits); } + digit_t sls_eval::random_bits() { + digit_t r = 0; + for (digit_t i = 0; i < sizeof(digit_t); ++i) + r ^= m_rand() << (8 * i); + return r; + } + bool sls_eval::try_repair(app* e, unsigned i) { if (is_fixed0(e->get_arg(i))) return false; @@ -781,10 +771,7 @@ namespace bv { VERIFY(bv.is_bit2bool(e, arg, idx)); return try_repair_bit2bool(wval0(e, 0), idx); } - case OP_BSDIV: - case OP_BSDIV_I: - case OP_BSDIV0: - return try_repair_sdiv(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BUDIV: case OP_BUDIV_I: case OP_BUDIV0: @@ -793,14 +780,6 @@ namespace bv { case OP_BUREM_I: case OP_BUREM0: return try_repair_urem(wval0(e), wval0(e, 0), wval0(e, 1), i); - case OP_BSREM: - case OP_BSREM_I: - case OP_BSREM0: - return try_repair_srem(wval0(e), wval0(e, 0), wval0(e, 1), i); - case OP_BSMOD: - case OP_BSMOD_I: - case OP_BSMOD0: - return try_repair_smod(wval0(e), wval0(e, 0), wval0(e, 1), i); case OP_ROTATE_LEFT: return try_repair_rotate_left(wval0(e), wval0(e, 0), e->get_parameter(0).get_int()); case OP_ROTATE_RIGHT: @@ -822,6 +801,19 @@ namespace bv { case OP_BSMUL_OVFL: case OP_BUMUL_NO_OVFL: case OP_BUMUL_OVFL: + return false; + case OP_BSREM: + case OP_BSREM_I: + case OP_BSREM0: + case OP_BSMOD: + case OP_BSMOD_I: + case OP_BSMOD0: + case OP_BSDIV: + case OP_BSDIV_I: + case OP_BSDIV0: + // these are currently compiled to udiv and urem. + UNREACHABLE(); + return false; default: return false; } @@ -922,13 +914,14 @@ namespace bv { // e = a & b // e[i] = 1 -> a[i] = 1 // e[i] = 0 & b[i] = 1 -> a[i] = 0 - // + // e[i] = 0 & b[i] = 0 -> a[i] = random // a := e[i] | (~b[i] & a[i]) bool sls_eval::try_repair_band(bvval const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = e.bits[i] | (~b.bits[i] & a.bits[i]); - return a.try_set(m_tmp); + m_tmp[i] = (e.bits[i] & ~a.fixed[i]) | (~b.bits[i] & ~a.fixed[i] & random_bits()); + a.set_repair(random_bool(), m_tmp); + return true; } // @@ -938,20 +931,23 @@ namespace bv { // bool sls_eval::try_repair_bor(bvval const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = e.bits[i] & (a.bits[i] | ~b.bits[i]); - return a.try_set(m_tmp); + m_tmp[i] = e.bits[i] & (~b.bits[i] | random_bits()); + a.set_repair(random_bool(), m_tmp); + return true; } bool sls_eval::try_repair_bxor(bvval const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < e.nw; ++i) m_tmp[i] = e.bits[i] ^ b.bits[i]; - return a.try_set(m_tmp); + a.set_repair(random_bool(), m_tmp); + return true; } + bool sls_eval::try_repair_add(bvval const& e, bvval& a, bvval const& b) { - digit_t c; - mpn.sub(e.bits.data(), e.nw, b.bits.data(), e.nw, m_tmp.data(), &c); - return a.try_set(m_tmp); + a.set_sub(m_tmp, e.bits, b.bits); + a.set_repair(random_bool(), m_tmp); + return true; } /** @@ -976,52 +972,84 @@ namespace bv { auto inv_b = nb.pseudo_inverse(b.bw); rational na = mod(inv_b * ne, rational::power_of_two(a.bw)); a.set_value(m_tmp, na); - return a.try_set(m_tmp); + a.set_repair(random_bool(), m_tmp); + return true; } bool sls_eval::try_repair_bnot(bvval const& e, bvval& a) { for (unsigned i = 0; i < e.nw; ++i) m_tmp[i] = ~e.bits[i]; - return a.try_set(m_tmp); + a.clear_overflow_bits(m_tmp); + a.set_repair(random_bool(), m_tmp); + return true; } bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { - digit_t c; - mpn.sub(m_zero.data(), e.nw, e.bits.data(), e.nw, m_tmp.data(), &c); - return a.try_set(m_tmp); + a.set_sub(m_tmp, m_zero, e.bits); + a.set_repair(random_bool(), m_tmp); + return true; } bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { - if (e) - return a.try_set(b.bits); - else { - digit_t c; - mpn.add(b.bits.data(), a.nw, m_one.data(), a.nw, &c, a.nw + 1, m_tmp.data()); - return a.try_set(m_tmp); - } + return try_repair_ule(e, a, b.bits); } bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) { - if (e) - return a.try_set(b.bits); - else { - digit_t c; - mpn.sub(b.bits.data(), a.nw, m_one.data(), a.nw, m_tmp.data(), &c); - return a.try_set(m_tmp); - } + return try_repair_uge(e, a, b.bits); } bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { - return try_repair_ule(e, a, b); + add_p2_1(b, m_tmp4); + return try_repair_ule(e, a, m_tmp4); } bool sls_eval::try_repair_sge(bool e, bvval& a, bvval const& b) { - return try_repair_uge(e, a, b); + add_p2_1(b, m_tmp4); + return try_repair_uge(e, a, m_tmp4); + } + + void sls_eval::add_p2_1(bvval const& a, svector& t) const { + a.set(m_zero, a.bw - 1, true); + a.set_add(t, a.bits, m_zero); + a.set(m_zero, a.bw - 1, false); + a.clear_overflow_bits(t); + } + + bool sls_eval::try_repair_ule(bool e, bvval& a, svector const& t) { + if (e) { + if (!a.get_at_most(t, m_tmp)) + return false; + } + else { + // a > b + a.set_add(m_tmp2, t, m_one); + if (a.is_zero(m_tmp2)) + return false; + if (!a.get_at_least(m_tmp2, m_tmp)) + return false; + } + a.set_repair(random_bool(), m_tmp2); + return true; + } + + bool sls_eval::try_repair_uge(bool e, bvval& a, svector const& t) { + if (e) { + if (!a.get_at_least(t, m_tmp)) + return false; + } + else { + if (a.is_zero(t)) + return false; + a.set_sub(m_tmp2, t, m_one); + if (!a.get_at_most(m_tmp2, m_tmp)) + return false; + } + a.set_repair(random_bool(), m_tmp); + return true; } bool sls_eval::try_repair_bit2bool(bvval& a, unsigned idx) { - for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = a.bits[i]; + a.set(m_tmp, a.bits); a.set(m_tmp, idx, !a.get(a.bits, idx)); return a.try_set(m_tmp); } @@ -1090,24 +1118,139 @@ namespace bv { return try_repair_ashr(e, a, b, i); } - bool sls_eval::try_repair_sdiv(bvval const& e, bvval& a, bvval& b, unsigned i) { - return false; - } + // e = a udiv b + // e = 0 => a != ones + // b = 0 => e = -1 // nothing to repair on a + // e != -1 => max(a) >=u e bool sls_eval::try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i) { - return false; + if (i == 0) { + if (e.is_zero() && a.is_ones(a.fixed) && a.is_ones()) + return false; + if (b.is_zero()) + return true; + if (!e.is_ones()) { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = ~a.fixed[i] | a.bits[i]; + a.clear_overflow_bits(m_tmp); + if (a.lt(m_tmp, e.bits)) + return false; + } + // e = 1 => a := b + if (e.is_one()) { + a.set(m_tmp, b.bits); + a.set_repair(false, m_tmp); + return true; + } + // y * e + r = a + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = random_bits(); + while (mul_overflow_on_fixed(e, m_tmp)) { + auto i = b.msb(m_tmp); + b.set(m_tmp, i, false); + } + for (unsigned i = 0; i < a.nw; ++i) + m_tmp2[i] = random_bits(); + while (b.gt(m_tmp2, b.bits)) + b.set(m_tmp2, b.msb(m_tmp2), false); + while (a.set_add(m_tmp3, m_tmp, m_tmp2)) + b.set(m_tmp2, b.msb(m_tmp2), false); + a.set_repair(true, m_tmp3); + } + else { + if (e.is_one()) { + b.set(m_tmp, a.bits); + b.set_repair(true, m_tmp); + return true; + } + // e * b + r = a + // b = (a - r) udiv e + // random version of r: + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = random_bits(); + a.clear_overflow_bits(m_tmp); + // ensure r <= a + while (a.lt(a.bits, m_tmp)) + a.set(m_tmp, a.msb(m_tmp), false); + a.set_sub(m_tmp2, a.bits, m_tmp); + mpn.div(m_tmp2.data(), a.nw, e.bits.data(), a.nw, m_tmp3.data(), m_tmp4.data()); + b.set_repair(random_bool(), m_tmp4); + } + return true; } - bool sls_eval::try_repair_smod(bvval const& e, bvval& a, bvval& b, unsigned i) { - return false; - } + // table III in Niemetz et al + // x urem s = t <=> + // ~(-s) >=u t + // ((s = 0 or t = ones) => mcb(x, t)) + // ((s != 0 and t != ones) => exists y . (mcb(x, s*y + t) and ~mulo(s, y) and ~addo(s*y, t)) + // s urem x = t <=> + // (s = t => x can be >u t) + // (s != t => exists y . (mcb(x, y) and y >u t and (s - t) mod y = 0) + bool sls_eval::try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i) { - return false; + + if (i == 0) { + if (b.is_zero()) { + a.set(m_tmp, e.bits); + a.set_repair(random_bool(), m_tmp); + return true; + } + // a urem b = e: b*y + e = a + // ~Ovfl*(b, y) + // ~Ovfl+(b*y, e) + // choose y at random + // lower y as long as y*b overflows with fixed bits in b + + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = random_bits(); + while (mul_overflow_on_fixed(b, m_tmp)) { + auto i = b.msb(m_tmp); + b.set(m_tmp, i, false); + } + while (true) { + a.set_mul(m_tmp2, m_tmp, b.bits); + a.clear_overflow_bits(m_tmp2); + if (!add_overflow_on_fixed(e, m_tmp2)) + break; + auto i = b.msb(m_tmp); + b.set(m_tmp, i, false); + } + a.set_add(m_tmp3, m_tmp2, e.bits); + a.set_repair(random_bool(), m_tmp3); + return true; + } + else { + // a urem b = e: b*y + e = a + // b*y = a - e + // b = (a - e) div y + // ~Ovfl*(b, y) + // ~Ovfl+(b*y, e) + // choose y at random + // lower y as long as y*b overflows with fixed bits in b + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = random_bits(); + a.set_sub(m_tmp2, a.bits, e.bits); + mpn.div(m_tmp2.data(), a.nw, m_tmp.data(), a.nw, m_tmp3.data(), m_tmp4.data()); + a.clear_overflow_bits(m_tmp3); + b.set_repair(random_bool(), m_tmp3); + return true; + } } - bool sls_eval::try_repair_srem(bvval const& e, bvval& a, bvval& b, unsigned i) { - return false; + bool sls_eval::add_overflow_on_fixed(bvval const& a, svector const& t) { + a.set(m_tmp3, m_zero); + for (unsigned i = 0; i < a.nw; ++i) + m_tmp3[i] = a.fixed[i] & a.bits[i]; + return a.set_add(m_tmp4, t, m_tmp3); + } + + bool sls_eval::mul_overflow_on_fixed(bvval const& a, svector const& t) { + a.set(m_tmp3, m_zero); + for (unsigned i = 0; i < a.nw; ++i) + m_tmp3[i] = a.fixed[i] & a.bits[i]; + return a.set_mul(m_tmp4, m_tmp3, t); } bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const { @@ -1116,8 +1259,9 @@ namespace bv { for (unsigned i = a.bw - n; i < a.bw; ++i) a.set(m_tmp, i + n - a.bw, e.get(e.bits, i)); for (unsigned i = 0; i < a.bw - n; ++i) - a.set(m_tmp, i + a.bw - n, e.get(e.bits, i)); - return a.try_set(m_tmp); + a.set(m_tmp, i + n, e.get(e.bits, i)); + a.set_repair(true, m_tmp); + return true; } bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i) { @@ -1131,7 +1275,8 @@ namespace bv { SASSERT(i == 1); unsigned sh = m_rand(b.bw); b.set(m_tmp, sh); - return b.try_set(m_tmp); + b.set_repair(random_bool(), m_tmp); + return true; } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 5fa51ed17..70a08283f 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -83,13 +83,19 @@ namespace bv { bool try_repair_ashr(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_bit2bool(bvval& a, unsigned idx); - bool try_repair_sdiv(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_smod(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_srem(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const; bool try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_ule(bool e, bvval& a, svector const& t); + bool try_repair_uge(bool e, bvval& a, svector const& t); + void add_p2_1(bvval const& a, svector& t) const; + + bool add_overflow_on_fixed(bvval const& a, svector const& t); + bool mul_overflow_on_fixed(bvval const& a, svector const& t); + + digit_t random_bits(); + bool random_bool() { return m_rand() % 2 == 0; } sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 4dafb6034..490557a56 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -54,6 +54,7 @@ namespace bv { void sls_fixed::init_range(app* e, bool sign) { expr* s, * t, * x, * y; rational a, b; + unsigned idx; auto N = [&](expr* s) { auto b = bv.get_bv_size(s); return b > 0 ? rational::power_of_two(b - 1) : rational(0); @@ -98,6 +99,19 @@ namespace bv { get_offset(t, y, b); init_range(x, a + N(s), y, b + N(s), !sign); } + else if (!sign && m.is_eq(e, s, t)) { + if (bv.is_numeral(s, a)) + // t - a <= 0 + init_range(t, -a, nullptr, rational(0), !sign); + else if (bv.is_numeral(t, a)) + init_range(s, -a, nullptr, rational(0), !sign); + } + else if (bv.is_bit2bool(e, s, idx)) { + auto& val = wval0(s); + val.set(val.bits, idx, !sign); + val.set(val.fixed, idx, true); + val.init_fixed(); + } } // @@ -167,6 +181,7 @@ namespace bv { auto& val_el = wval0(e->get_arg(2)); for (unsigned i = 0; i < val.nw; ++i) val.fixed[i] = val_el.fixed[i] & val_th.fixed[i] & ~(val_el.bits[i] ^ val_th.bits[i]); + val.init_fixed(); } } @@ -224,6 +239,13 @@ namespace bv { v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & a.bits[i]) | (b.fixed[i] & b.bits[i]); break; } + case OP_BXOR: { + auto& a = wval0(e->get_arg(0)); + auto& b = wval0(e->get_arg(1)); + for (unsigned i = 0; i < a.nw; ++i) + v.fixed[i] = a.fixed[i] & b.fixed[i]; + break; + } case OP_BNOT: { auto& a = wval0(e->get_arg(0)); for (unsigned i = 0; i < a.nw; ++i) @@ -331,9 +353,9 @@ namespace bv { // if 0 < b < v.bw is known, then inherit shift of fixed values of a // if 0 < b < v.bw but not known, then inherit run lengths of equal bits of a // that are fixed. - NOT_IMPLEMENTED_YET(); break; } + case OP_BASHR: case OP_BLSHR: case OP_INT2BV: @@ -352,10 +374,9 @@ namespace bv { case OP_BUREM0: case OP_BSMOD: case OP_BSMOD_I: - case OP_BSMOD0: - case OP_BXOR: + case OP_BSMOD0: case OP_BXNOR: - NOT_IMPLEMENTED_YET(); + // NOT_IMPLEMENTED_YET(); break; case OP_BV_NUM: case OP_BIT0: @@ -381,6 +402,7 @@ namespace bv { case OP_SLT: UNREACHABLE(); break; - } + } + v.init_fixed(); } } diff --git a/src/ast/sls/bv_sls_terms.cpp b/src/ast/sls/bv_sls_terms.cpp index 422b2017e..0a110a7d8 100644 --- a/src/ast/sls/bv_sls_terms.cpp +++ b/src/ast/sls/bv_sls_terms.cpp @@ -66,6 +66,7 @@ namespace bv { }; unsigned num_args = a->get_num_args(); expr_ref r(m); + expr* x, * y; #define FOLD_OP(oper) \ r = arg(0); \ for (unsigned i = 1; i < num_args; ++i)\ @@ -98,6 +99,15 @@ namespace bv { else if (bv.is_concat(e)) { FOLD_OP(bv.mk_concat); } + else if (bv.is_bv_sdiv(e, x, y) || bv.is_bv_sdiv0(e, x, y) || bv.is_bv_sdivi(e, x, y)) { + r = mk_sdiv(x, y); + } + else if (bv.is_bv_smod(e, x, y) || bv.is_bv_smod0(e, x, y) || bv.is_bv_smodi(e, x, y)) { + r = mk_smod(x, y); + } + else if (bv.is_bv_srem(e, x, y) || bv.is_bv_srem0(e, x, y) || bv.is_bv_sremi(e, x, y)) { + r = mk_srem(x, y); + } else { for (unsigned i = 0; i < num_args; ++i) m_todo.push_back(arg(i)); @@ -107,6 +117,60 @@ namespace bv { m_translated.setx(e->get_id(), r); } + expr* sls_terms::mk_sdiv(expr* x, expr* y) { + // d = udiv(abs(x), abs(y)) + // y = 0, x > 0 -> 1 + // y = 0, x <= 0 -> -1 + // x = 0, y != 0 -> 0 + // x > 0, y < 0 -> -d + // x < 0, y > 0 -> -d + // x > 0, y > 0 -> d + // x < 0, y < 0 -> d + unsigned sz = bv.get_bv_size(x); + rational N = rational::power_of_two(sz); + expr_ref z(bv.mk_zero(sz), m); + expr* signx = bv.mk_ule(bv.mk_numeral(N / 2, sz), x); + expr* signy = bv.mk_ule(bv.mk_numeral(N / 2, sz), y); + expr* absx = m.mk_ite(signx, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), x), x); + expr* absy = m.mk_ite(signy, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), y), y); + expr* d = bv.mk_bv_udiv(absx, absy); + expr* r = m.mk_ite(m.mk_eq(signx, signy), d, bv.mk_bv_neg(d)); + r = m.mk_ite(m.mk_eq(z, y), + m.mk_ite(signx, bv.mk_numeral(N - 1, sz), bv.mk_one(sz)), + m.mk_ite(m.mk_eq(x, z), z, r)); + return r; + } + + expr* sls_terms::mk_smod(expr* x, expr* y) { + // u := umod(abs(x), abs(y)) + // u = 0 -> 0 + // y = 0 -> x + // x < 0, y < 0 -> -u + // x < 0, y >= 0 -> y - u + // x >= 0, y < 0 -> y + u + // x >= 0, y >= 0 -> u + unsigned sz = bv.get_bv_size(x); + expr_ref z(bv.mk_zero(sz), m); + expr_ref abs_x(m.mk_ite(bv.mk_sle(z, x), x, bv.mk_bv_neg(x)), m); + expr_ref abs_y(m.mk_ite(bv.mk_sle(z, y), y, bv.mk_bv_neg(y)), m); + expr_ref u(bv.mk_bv_urem(abs_x, abs_y), m); + return + m.mk_ite(m.mk_eq(u, z), z, + m.mk_ite(m.mk_eq(y, z), x, + m.mk_ite(m.mk_and(bv.mk_sle(z, x), bv.mk_sle(z, x)), u, + m.mk_ite(bv.mk_sle(z, x), bv.mk_bv_add(y, u), + m.mk_ite(bv.mk_sle(z, y), bv.mk_bv_sub(y, u), bv.mk_bv_neg(u)))))); + + } + + expr* sls_terms::mk_srem(expr* x, expr* y) { + // y = 0 -> x + // else x - sdiv(x, y) * y + return + m.mk_ite(m.mk_eq(y, bv.mk_zero(bv.get_bv_size(x))), + x, bv.mk_bv_sub(x, bv.mk_bv_mul(y, mk_sdiv(x, y)))); + } + void sls_terms::init() { // populate terms diff --git a/src/ast/sls/bv_sls_terms.h b/src/ast/sls/bv_sls_terms.h index 688047846..95d9a508e 100644 --- a/src/ast/sls/bv_sls_terms.h +++ b/src/ast/sls/bv_sls_terms.h @@ -40,6 +40,10 @@ namespace bv { expr* ensure_binary(expr* e); void ensure_binary_core(expr* e); + expr* mk_sdiv(expr* x, expr* y); + expr* mk_smod(expr* x, expr* y); + expr* mk_srem(expr* x, expr* y); + public: sls_terms(ast_manager& m); @@ -65,6 +69,5 @@ namespace bv { bool is_assertion(expr* e) const { return m_assertion_set.contains(e->get_id()); } - }; } diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index fb2c8f129..75307c667 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -33,15 +33,13 @@ namespace bv { for (unsigned i = 0; i < nw; ++i) lo[i] = 0, hi[i] = 0, bits[i] = 0, fixed[i] = 0; for (unsigned i = bw; i < 8 * sizeof(digit_t) * nw; ++i) - set(fixed, i, false); - } - - sls_valuation::~sls_valuation() { + set(fixed, i, true); } bool sls_valuation::in_range(svector const& bits) const { mpn_manager m; auto c = m.compare(lo.data(), nw, hi.data(), nw); + SASSERT(!has_overflow(bits)); // full range if (c == 0) return true; @@ -56,44 +54,187 @@ namespace bv { m.compare(bits.data(), nw, hi.data(), nw) < 0; } - bool sls_valuation::eq(svector const& other) const { - auto c = 0 == memcmp(bits.data(), other.data(), bw / 8); - if (bw % 8 == 0 || !c) - return c; - for (unsigned i = 8 * (bw / 8); i < bw; ++i) - if (get(bits, i) != get(other, i)) - return false; - return true; + bool sls_valuation::eq(svector const& a, svector const& b) const { + SASSERT(!has_overflow(a)); + SASSERT(!has_overflow(b)); + return 0 == memcmp(a.data(), b.data(), num_bytes()); } bool sls_valuation::gt(svector const& a, svector const& b) const { + SASSERT(!has_overflow(a)); + SASSERT(!has_overflow(b)); mpn_manager m; return m.compare(a.data(), nw, b.data(), nw) > 0; } + bool sls_valuation::lt(svector const& a, svector const& b) const { + SASSERT(!has_overflow(a)); + SASSERT(!has_overflow(b)); + mpn_manager m; + return m.compare(a.data(), nw, b.data(), nw) < 0; + } + + bool sls_valuation::le(svector const& a, svector const& b) const { + SASSERT(!has_overflow(a)); + SASSERT(!has_overflow(b)); + mpn_manager m; + return m.compare(a.data(), nw, b.data(), nw) <= 0; + } + void sls_valuation::clear_overflow_bits(svector& bits) const { for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) set(bits, i, false); + SASSERT(!has_overflow(bits)); } - bool sls_valuation::get_below(svector const& src, svector& dst) { - for (unsigned i = 0; i < nw; ++i) - dst[i] = (src[i] & ~fixed[i]) | (fixed[i] & bits[i]); - for (unsigned i = 0; i < nw; ++i) - dst[i] = fixed[i] & bits[i]; - if (gt(dst, src)) - return false; - if (!in_range(dst)) { - // lo < hi: - // set dst to lo, except for fixed bits - // - if (gt(hi, lo)) { + // + // largest dst <= src and dst is feasible + // set dst := src & (~fixed | bits) + // + // increment dst if dst < src by setting bits below msb(src & ~dst) to 1 + // + // if dst < lo < hi: + // return false + // if lo < hi <= dst: + // set dst := hi - 1 + // if hi <= dst < lo + // set dst := hi - 1 + // + bool sls_valuation::get_at_most(svector const& src, svector& dst) const { + SASSERT(!has_overflow(src)); + for (unsigned i = 0; i < nw; ++i) + dst[i] = src[i] & (~fixed[i] | bits[i]); + + // + // If dst < src, then find the most significant + // bit where src[idx] = 1, dst[idx] = 0 + // set dst[j] = bits_j | ~fixed_j for j < idx + // + for (unsigned i = nw; i-- > 0; ) { + if (0 != (~dst[i] & src[i])) { + auto idx = log2(~dst[i] & src[i]); + auto mask = (1 << idx) - 1; + dst[i] = (~fixed[i] & mask) | dst[i]; + for (unsigned j = i; j-- > 0; ) + dst[j] = (~fixed[j] | bits[j]); + break; } - } + } + SASSERT(!has_overflow(dst)); + return round_down(dst); + } + + // + // smallest dst >= src and dst is feasible with respect to this. + // set dst := (src & ~fixed) | (fixed & bits) + // + // decrement dst if dst > src by setting bits below msb to 0 unless fixed + // + // if lo < hi <= dst + // return false + // if dst < lo < hi: + // set dst := lo + // if hi <= dst < lo + // set dst := lo + // + bool sls_valuation::get_at_least(svector const& src, svector& dst) const { + SASSERT(!has_overflow(src)); + for (unsigned i = 0; i < nw; ++i) + dst[i] = (~fixed[i] & src[i]) | (fixed[i] & bits[i]); + + // + // If dst > src, then find the most significant + // bit where src[idx] = 0, dst[idx] = 1 + // set dst[j] = dst[j] & fixed_j for j < idx + // + for (unsigned i = nw; i-- > 0; ) { + if (0 != (dst[i] & ~src[i])) { + auto idx = log2(dst[i] & ~src[i]); + auto mask = (1 << idx); + dst[i] = dst[i] & (fixed[i] | mask); + for (unsigned j = i; j-- > 0; ) + dst[j] = dst[j] & fixed[j]; + break; + } + } + SASSERT(!has_overflow(dst)); + return round_up(dst); + } + + bool sls_valuation::round_up(svector& dst) const { + if (lt(lo, hi)) { + if (le(hi, dst)) + return false; + if (lt(dst, lo)) + set(dst, lo); + } + else if (le(hi, dst) && lt(dst, lo)) + set(dst, lo); + SASSERT(!has_overflow(dst)); return true; } + bool sls_valuation::round_down(svector& dst) const { + if (lt(lo, hi)) { + if (lt(lo, hi)) + return false; + if (le(hi, dst)) { + set(dst, hi); + sub1(dst); + } + } + else if (le(hi, dst) && lt(dst, lo)) { + set(dst, hi); + sub1(dst); + } + SASSERT(!has_overflow(dst)); + return true; + } + + void sls_valuation::set_repair(bool try_down, svector& dst) { + for (unsigned i = 0; i < nw; ++i) + dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & bits[i]); + bool ok = try_down ? round_down(dst) : round_up(dst); + if (!ok) + VERIFY(try_down ? round_up(dst) : round_down(dst)); + set(bits, dst); + SASSERT(!has_overflow(dst)); + } + + void sls_valuation::min_feasible(svector& out) const { + if (gt(hi, lo)) { + for (unsigned i = 0; i < nw; ++i) + out[i] = lo[i]; + } + else { + for (unsigned i = 0; i < nw; ++i) + out[i] = fixed[i] & bits[i]; + } + SASSERT(!has_overflow(out)); + } + + void sls_valuation::max_feasible(svector& out) const { + if (gt(hi, lo)) { + for (unsigned i = 0; i < nw; ++i) + out[i] = hi[i]; + sub1(out); + } + else { + for (unsigned i = 0; i < nw; ++i) + out[i] = ~fixed[i] | bits[i]; + } + SASSERT(!has_overflow(out)); + } + + unsigned sls_valuation::msb(svector const& src) const { + SASSERT(!has_overflow(src)); + for (unsigned i = nw; i-- > 0; ) + if (src[i] != 0) + return i * 8 * sizeof(digit_t) + log2(src[i]); + return bw; + } + void sls_valuation::set_value(svector& bits, rational const& n) { for (unsigned i = 0; i < bw; ++i) set(bits, i, n.get_bit(i)); @@ -123,7 +264,8 @@ namespace bv { // 0 = (new_bits ^ bits) & fixed // also check that new_bits are in range // - bool sls_valuation::can_set(svector const& new_bits) const { + bool sls_valuation::can_set(svector const& new_bits) const { + SASSERT(!has_overflow(new_bits)); for (unsigned i = 0; i < nw; ++i) if (0 != ((new_bits[i] ^ bits[i]) & fixed[i])) return false; @@ -131,6 +273,7 @@ namespace bv { } unsigned sls_valuation::to_nat(svector const& d, unsigned max_n) { + SASSERT(!has_overflow(d)); SASSERT(max_n < UINT_MAX / 2); unsigned p = 1; unsigned value = 0; @@ -156,12 +299,129 @@ namespace bv { if (eq(lo, hi)) { set_value(lo, l); set_value(hi, h); - return; } - - // TODO: intersect with previous range, if any - set_value(lo, l); - set_value(hi, h); + else { + rational old_lo, old_hi; + get_value(lo, old_lo); + get_value(hi, old_hi); + if (old_lo < old_hi) { + if (old_lo < l && l < old_hi) + set_value(lo, l), + old_lo = l; + if (old_hi < h && h < old_hi) + set_value(hi, h); + } + else { + SASSERT(old_hi < old_lo); + if (old_lo < l || l < old_hi) + set_value(lo, l), + old_lo = l; + if (old_lo < h && h < old_hi) + set_value(hi, h); + else if (old_hi < old_lo && (h < old_hi || old_lo < h)) + set_value(hi, h); + } + } + SASSERT(!has_overflow(lo)); + SASSERT(!has_overflow(hi)); + } + + void sls_valuation::init_fixed() { + if (eq(lo, hi)) + return; + bool lo_ok = true; + for (unsigned i = 0; i < nw; ++i) + lo_ok &= (0 == (fixed[i] & (bits[i] ^ lo[i]))); + if (!lo_ok) { + svector tmp(nw + 1); + if (get_at_least(lo, tmp)) { + if (lt(lo, hi) && lt(tmp, hi)) + set(lo, tmp); + else if (gt(lo, hi)) + set(lo, tmp); + } + else if (gt(lo, hi)) { + svector zero(nw + 1, (unsigned) 0); + if (get_at_least(zero, tmp) && lt(tmp, hi)) + set(lo, tmp); + } + } + bool hi_ok = true; + svector hi1(nw + 1, (unsigned)0); + svector one(nw + 1, (unsigned)0); + one[0] = 1; + digit_t c; + mpn_manager().sub(hi.data(), nw, one.data(), nw, hi1.data(), &c); + for (unsigned i = 0; i < nw; ++i) + hi_ok &= (0 == (fixed[i] & (bits[i] ^ hi1[i]))); + if (!hi_ok) { + svector tmp(nw + 1); + if (get_at_most(hi1, tmp)) { + if (lt(tmp, hi) && (le(lo, tmp) || lt(hi, lo))) { + mpn_manager().add(tmp.data(), nw, one.data(), nw, hi1.data(), nw + 1, &c); + clear_overflow_bits(hi1); + set(hi, hi1); + } + } + // TODO other cases + } + + // set most significant bits + if (lt(lo, hi)) { + unsigned i = bw; + for (; i-- > 0; ) { + if (get(hi, i)) + break; + if (!get(fixed, i)) { + set(fixed, i, true); + set(bits, i, false); + } + } + bool is_power_of2 = true; + for (unsigned j = 0; is_power_of2 && j < i; ++j) + is_power_of2 = !get(hi, j); + if (is_power_of2) { + if (!get(fixed, i)) { + set(fixed, i, true); + set(bits, i, false); + } + } + } + svector tmp(nw + 1, (unsigned)0); + mpn_manager().add(lo.data(), nw, one.data(), nw, tmp.data(), nw + 1, &c); + clear_overflow_bits(tmp); + if (eq(tmp, hi)) { + for (unsigned i = 0; i < bw; ++i) { + if (!get(fixed, i)) { + set(fixed, i, true); + set(bits, i, get(lo, i)); + } + } + } + SASSERT(!has_overflow(bits)); + } + + void sls_valuation::set_sub(svector& out, svector const& a, svector const& b) const { + digit_t c; + mpn_manager().sub(a.data(), nw, b.data(), nw, out.data(), &c); + clear_overflow_bits(out); + } + + bool sls_valuation::set_add(svector& out, svector const& a, svector const& b) const { + digit_t c; + mpn_manager().add(a.data(), nw, b.data(), nw, out.data(), nw + 1, &c); + bool ovfl = out[nw] != 0 || has_overflow(out); + clear_overflow_bits(out); + return ovfl; + } + + bool sls_valuation::set_mul(svector& out, svector const& a, svector const& b) const { + mpn_manager().mul(a.data(), nw, b.data(), nw, out.data()); + bool ovfl = has_overflow(out); + for (unsigned i = nw; i < 2 * nw; ++i) + ovfl |= out[i] != 0; + clear_overflow_bits(out); + return ovfl; } } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 34ab55f61..6a5b241b3 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -33,7 +33,6 @@ namespace bv { svector lo, hi; // range assignment to bit-vector, as wrap-around interval svector bits, fixed; // bit assignment and don't care bit sls_valuation(unsigned bw); - ~sls_valuation(); unsigned num_bytes() const { return (bw + 7) / 8; } @@ -41,6 +40,7 @@ namespace bv { void get_value(svector const& bits, rational& r) const; void get(svector& dst) const; void add_range(rational lo, rational hi); + void init_fixed(); void set1(svector& bits); void clear_overflow_bits(svector& bits) const; @@ -52,6 +52,8 @@ namespace bv { bool eq(svector const& other) const { return eq(other, bits); } bool eq(svector const& a, svector const& b) const; bool gt(svector const& a, svector const& b) const; + bool lt(svector const& a, svector const& b) const; + bool le(svector const& a, svector const& b) const; bool is_zero() const { return is_zero(bits); } bool is_zero(svector const& a) const { @@ -60,6 +62,29 @@ namespace bv { return false; return true; } + bool is_ones() const { return is_ones(bits); } + bool is_ones(svector const& a) const { + auto bound = bw % (sizeof(digit_t) * 8) == 0 ? nw : nw - 1; + for (unsigned i = 0; i < bound; ++i) + if (a[i] != ~0) + return false; + if (bound < nw) { + for (unsigned i = bound * sizeof(digit_t) * 8; i < bw; ++i) + if (!get(a, i)) + return false; + } + return true; + } + + bool is_one() const { return is_one(bits); } + bool is_one(svector const& bits) const { + if (1 != bits[0]) + return false; + for (unsigned i = 1; i < nw; ++i) + if (0 != bits[i]) + return false; + return true; + } bool sign() const { return get(bits, bw - 1); } @@ -71,14 +96,25 @@ namespace bv { } unsigned parity(svector const& bits) const { - unsigned i = 0; - for (; i < bw && !get(bits, i); ++i); - return i; + for (unsigned i = 0; i < nw; ++i) + if (bits[i] != 0) + return (8 * sizeof(digit_t) * i) + trailing_zeros(bits[i]); + return bw; } - // retrieve number at or below src which is feasible + void min_feasible(svector& out) const; + void max_feasible(svector& out) const; + + // most significant bit or bw if src = 0 + unsigned msb(svector const& src) const; + + // retrieve largest number at or below (above) src which is feasible // with respect to fixed, lo, hi. - bool get_below(svector const& src, svector& dst); + bool get_at_most(svector const& src, svector& dst) const; + bool get_at_least(svector const& src, svector& dst) const; + bool round_up(svector& dst) const; + bool round_down(svector& dst) const; + void set_repair(bool try_down, svector& dst); bool try_set(svector const& src) { if (!can_set(src)) @@ -98,12 +134,21 @@ namespace bv { bits[i] = 0; } - - void set_fixed(svector const& src) { - for (unsigned i = nw; i-- > 0; ) - fixed[i] = src[i]; + void sub1(svector& out) const { + for (unsigned i = 0; i < bw; ++i) { + if (get(out, i)) { + set(out, i, false); + return; + } + else + set(out, i, true); + } } + void set_sub(svector& out, svector const& a, svector const& b) const; + bool set_add(svector& out, svector const& a, svector const& b) const; + bool set_mul(svector& out, svector const& a, svector const& b) const; + void set_range(svector& dst, unsigned lo, unsigned hi, bool b) { for (unsigned i = lo; i < hi; ++i) set(dst, i, b); @@ -120,6 +165,11 @@ namespace bv { dst[i] = 0; } + void set(svector& dst, svector const& src) const { + for (unsigned i = 0; i < nw; ++i) + dst[i] = src[i]; + } + bool get(svector const& d, unsigned bit_idx) const { return (get_bit_word(d, bit_idx) & get_pos_mask(bit_idx)) != 0; } diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp index 8e9cc10ad..3b0fd580a 100644 --- a/src/test/sls_test.cpp +++ b/src/test/sls_test.cpp @@ -84,7 +84,7 @@ namespace bv { .push_back(bv.mk_ule(a, b)) .push_back(bv.mk_sle(a, b)) .push_back(bv.mk_concat(a, b)) - .push_back(bv.mk_extract(6, 3, a)) + .push_back(bv.mk_extract(4, 2, a)) .push_back(bv.mk_bvuadd_ovfl(a, b)) .push_back(bv.mk_bv_rotate_left(a, j)) .push_back(bv.mk_bv_rotate_right(a, j)) @@ -97,6 +97,7 @@ namespace bv { // .push_back(bv.mk_bvsmul_ovfl(a, b)) // .push_back(bv.mk_bvsdiv_ovfl(a, b)) ; + return result; } From 991537836b1ee8b96a00850f6554b4c5a881a0a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Feb 2024 12:59:28 +0700 Subject: [PATCH 15/69] fixes based on unit tests --- src/ast/bv_decl_plugin.h | 14 +-- src/ast/sls/bv_sls.cpp | 53 ++++++++- src/ast/sls/bv_sls.h | 3 + src/ast/sls/bv_sls_eval.cpp | 215 ++++++++++++++++++++++++++++------ src/ast/sls/bv_sls_eval.h | 8 ++ src/ast/sls/bv_sls_fixed.cpp | 1 + src/ast/sls/bv_sls_terms.cpp | 6 +- src/ast/sls/sls_valuation.cpp | 126 +++++++++++--------- src/ast/sls/sls_valuation.h | 12 ++ src/test/sls_test.cpp | 36 ++++-- 10 files changed, 363 insertions(+), 111 deletions(-) diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 41c2ef752..137dc754f 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -557,15 +557,15 @@ public: app* mk_bv_rotate_right(expr* arg, unsigned n); // TODO: all these binary ops commute (right?) but it'd be more logical to swap `n` & `m` in the `return` - app * mk_bvsmul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_OVFL, n, m); } - app * mk_bvsmul_no_udfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_UDFL, n, m); } - app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); } - app * mk_bvsmul_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_OVFL, n, m); } - app * mk_bvumul_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_OVFL, n, m); } + app * mk_bvsmul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_OVFL, m, n); } + app * mk_bvsmul_no_udfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_UDFL, m, n); } + app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, m, n); } + app * mk_bvsmul_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_OVFL, m, n); } + app * mk_bvumul_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_OVFL, m, n); } app * mk_bvsdiv_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSDIV_OVFL, m, n); } app * mk_bvneg_ovfl(expr* m) { return m_manager.mk_app(get_fid(), OP_BNEG_OVFL, m); } - app * mk_bvuadd_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUADD_OVFL, n, m); } - app * mk_bvsadd_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSADD_OVFL, n, m); } + app * mk_bvuadd_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUADD_OVFL, m, n); } + app * mk_bvsadd_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSADD_OVFL, m, n); } app * mk_bvusub_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUSUB_OVFL, m, n); } app * mk_bvssub_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSSUB_OVFL, m, n); } diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 6ba3d734e..0b136d390 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -46,6 +46,31 @@ namespace bv { m_eval.init_fixed(m_terms.assertions()); } + void sls::reinit_eval() { + std::function eval = [&](expr* e, unsigned i) { + if (m.is_bool(e)) { + if (m_eval.is_fixed0(e)) + return m_eval.bval0(e); + } + else if (bv.is_bv(e)) { + auto& w = m_eval.wval0(e); + if (w.get(w.fixed, i)) + return w.get(w.bits, i); + + } + return m_rand() % 2 == 0; + }; + m_eval.init_eval(m_terms.assertions(), eval); + m_repair_down.reset(); + m_repair_up.reset(); + for (auto* e : m_terms.assertions()) { + if (!m_eval.bval0(e)) { + m_eval.set(e, true); + m_repair_down.insert(e->get_id()); + } + } + } + std::pair sls::next_to_repair() { app* e = nullptr; if (!m_repair_down.empty()) { @@ -59,7 +84,7 @@ namespace bv { return { !m_repair_down.empty(), e }; } - lbool sls::operator()() { + lbool sls::search() { // init and init_eval were invoked. unsigned& n = m_stats.m_moves; n = 0; @@ -67,7 +92,7 @@ namespace bv { auto [down, e] = next_to_repair(); if (!e) return l_true; - IF_VERBOSE(20, verbose_stream() << (down?"d ":"u ") << mk_bounded_pp(e, m, 1) << "\n"); + IF_VERBOSE(20, verbose_stream() << (down ? "d " : "u ") << mk_bounded_pp(e, m, 1) << "\n"); if (eval_is_correct(e)) { if (down) m_repair_down.remove(e->get_id()); @@ -75,14 +100,32 @@ namespace bv { m_repair_up.remove(e->get_id()); } else if (down) { - try_repair_down(e); + try_repair_down(e); } - else - try_repair_up(e); + else + try_repair_up(e); } return l_undef; } + lbool sls::operator()() { + lbool res = l_undef; + do { + if (!m.inc()) + return l_undef; + + res = search(); + + if (res != l_undef) + return res; + + reinit_eval(); + } + while (m_stats.m_restarts++ < m_config.m_max_restarts); + + return res; + } + void sls::try_repair_down(app* e) { unsigned n = e->get_num_args(); if (n > 0) { diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index 781174aee..c91838a4c 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -57,6 +57,9 @@ namespace bv { bool try_repair_down(app* e, unsigned i); + lbool search(); + void reinit_eval(); + public: sls(ast_manager& m); diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 576c0a89e..3f5d0e270 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -319,7 +319,7 @@ namespace bv { else b.get(m_tmp2); - mpn.div(m_tmp.data(), a.nw, m_tmp2.data(), a.nw, m_tmp3.data(), m_tmp4.data()); + set_div(m_tmp, m_tmp2, a.bw, m_tmp3, m_tmp4); if (sign_a == sign_b) val.set(m_tmp3); else @@ -500,10 +500,7 @@ namespace bv { if (b.is_zero()) val.set(a.bits); else { - mpn.div(a.bits.data(), a.nw, - b.bits.data(), b.nw, - m_tmp.data(), // quotient - m_tmp2.data()); // remainder + set_div(a.bits, b.bits, b.bw, m_tmp, m_tmp2); val.set(m_tmp2); } break; @@ -530,11 +527,8 @@ namespace bv { if (b.sign()) b.set_sub(m_tmp4, m_zero, b.bits); else - a.set(m_tmp4, b.bits); - mpn.div(m_tmp3.data(), a.nw, - m_tmp4.data(), b.nw, - m_tmp.data(), // quotient - m_tmp2.data()); // remainder + a.set(m_tmp4, b.bits); + set_div(m_tmp3, m_tmp4, a.bw, m_tmp, m_tmp2); if (val.is_zero(m_tmp2)) val.set(m_tmp2); else if (a.sign() && b.sign()) @@ -557,10 +551,7 @@ namespace bv { if (b.is_zero()) val.set(m_minus_one); else { - mpn.div(a.bits.data(), a.nw, - b.bits.data(), b.nw, - m_tmp.data(), // quotient - m_tmp2.data()); // remainder + set_div(a.bits, b.bits, a.bw, m_tmp, m_tmp2); val.set(m_tmp); } break; @@ -705,6 +696,8 @@ namespace bv { return try_repair_bxor(wval0(e), wval0(e, i), wval0(e, 1 - i)); case OP_BADD: return try_repair_add(wval0(e), wval0(e, i), wval0(e, 1 - i)); + case OP_BSUB: + return try_repair_sub(wval0(e), wval0(e, 0), wval0(e, 1), i); case OP_BMUL: return try_repair_mul(wval0(e), wval0(e, i), wval0(e, 1 - i)); case OP_BNOT: @@ -787,20 +780,35 @@ namespace bv { case OP_EXT_ROTATE_LEFT: return try_repair_rotate_left(wval0(e), wval0(e, 0), wval0(e, 1), i); case OP_EXT_ROTATE_RIGHT: - case OP_BCOMP: + return try_repair_rotate_right(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_ZERO_EXT: + return try_repair_zero_ext(wval0(e), wval0(e, 0)); + case OP_SIGN_EXT: + return try_repair_zero_ext(wval0(e), wval0(e, 0)); + case OP_CONCAT: + return try_repair_concat(wval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_EXTRACT: { + unsigned hi, lo; + expr* arg; + VERIFY(bv.is_extract(e, lo, hi, arg)); + return try_repair_extract(wval0(e), wval0(arg), lo); + } + case OP_BUMUL_NO_OVFL: + return try_repair_umul_ovfl(!bval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BUMUL_OVFL: + return try_repair_umul_ovfl(bval0(e), wval0(e, 0), wval0(e, 1), i); + case OP_BUADD_OVFL: + case OP_BCOMP: case OP_BNAND: case OP_BREDAND: case OP_BREDOR: case OP_BXNOR: case OP_BNEG_OVFL: case OP_BSADD_OVFL: - case OP_BUADD_OVFL: case OP_BSDIV_OVFL: case OP_BSMUL_NO_OVFL: case OP_BSMUL_NO_UDFL: case OP_BSMUL_OVFL: - case OP_BUMUL_NO_OVFL: - case OP_BUMUL_OVFL: return false; case OP_BSREM: case OP_BSREM_I: @@ -950,6 +958,21 @@ namespace bv { return true; } + + bool sls_eval::try_repair_sub(bvval const& e, bvval& a, bvval & b, unsigned i) { + if (i == 0) { + // e = a - b -> a := e + b + a.set_add(m_tmp, e.bits, b.bits); + a.set_repair(random_bool(), m_tmp); + } + else { + // b := a - e + a.set_sub(m_tmp, a.bits, e.bits); + a.set_repair(random_bool(), m_tmp); + } + return true; + } + /** * e = a*b, then a = e * b^-1 * 8*e = a*(2b), then a = 4e*b^-1 @@ -998,14 +1021,31 @@ namespace bv { return try_repair_uge(e, a, b.bits); } + // a <=s b <-> a + p2 <=u b + p2 + bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { - add_p2_1(b, m_tmp4); - return try_repair_ule(e, a, m_tmp4); + //add_p2_1(b, m_tmp4); + a.set(m_tmp, b.bits); + if (e) { + a.set_repair(true, m_tmp); + } + else { + a.set_add(m_tmp2, m_tmp, m_one); + a.set_repair(false, m_tmp2); + } + return true; } bool sls_eval::try_repair_sge(bool e, bvval& a, bvval const& b) { - add_p2_1(b, m_tmp4); - return try_repair_uge(e, a, m_tmp4); + a.set(m_tmp, b.bits); + if (e) { + a.set_repair(false, m_tmp); + } + else { + a.set_sub(m_tmp2, m_tmp, m_one); + a.set_repair(true, m_tmp2); + } + return true; } void sls_eval::add_p2_1(bvval const& a, svector& t) const { @@ -1025,10 +1065,12 @@ namespace bv { a.set_add(m_tmp2, t, m_one); if (a.is_zero(m_tmp2)) return false; - if (!a.get_at_least(m_tmp2, m_tmp)) - return false; + if (!a.get_at_least(m_tmp2, m_tmp)) { + verbose_stream() << "could not get at least\n"; + return false; + } } - a.set_repair(random_bool(), m_tmp2); + a.set_repair(random_bool(), m_tmp); return true; } @@ -1090,15 +1132,28 @@ namespace bv { unsigned sh = b.to_nat(b.bits, b.bw); if (sh == 0) return a.try_set(e.bits); - else if (sh >= b.bw) - return false; + else if (sh >= b.bw) { + if (e.get(e.bits, e.bw - 1)) { + if (!a.get(a.bits, a.bw - 1) && !a.get(a.fixed, a.bw - 1)) + a.set(a.bits, a.bw - 1, true); + else + return false; + } + else { + if (a.get(a.bits, a.bw - 1) && !a.get(a.fixed, a.bw - 1)) + a.set(a.bits, a.bw - 1, false); + else + return false; + } + return true; + } else { // e = a >> sh // a[bw-1:sh] = e[bw-sh-1:0] // a[sh-1:0] = a[sh-1:0] // ignore sign - for (unsigned i = 0; i < a.bw - sh; ++i) - a.set(m_tmp, i + sh, e.get(e.bits, i)); + for (unsigned i = sh; i < a.bw; ++i) + a.set(m_tmp, i, e.get(e.bits, i - sh)); for (unsigned i = 0; i < sh; ++i) a.set(m_tmp, i, a.get(a.bits, i)); return a.try_set(m_tmp); @@ -1142,15 +1197,17 @@ namespace bv { a.set_repair(false, m_tmp); return true; } - // y * e + r = a + // b * e + r = a for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = random_bits(); + m_tmp[i] = (random_bits() & ~b.fixed[i]) | (b.fixed[i] & b.bits[i]); + b.clear_overflow_bits(m_tmp); while (mul_overflow_on_fixed(e, m_tmp)) { auto i = b.msb(m_tmp); b.set(m_tmp, i, false); } for (unsigned i = 0; i < a.nw; ++i) m_tmp2[i] = random_bits(); + b.clear_overflow_bits(m_tmp2); while (b.gt(m_tmp2, b.bits)) b.set(m_tmp2, b.msb(m_tmp2), false); while (a.set_add(m_tmp3, m_tmp, m_tmp2)) @@ -1169,11 +1226,11 @@ namespace bv { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = random_bits(); a.clear_overflow_bits(m_tmp); - // ensure r <= a + // ensure r <= m while (a.lt(a.bits, m_tmp)) a.set(m_tmp, a.msb(m_tmp), false); a.set_sub(m_tmp2, a.bits, m_tmp); - mpn.div(m_tmp2.data(), a.nw, e.bits.data(), a.nw, m_tmp3.data(), m_tmp4.data()); + set_div(m_tmp2, e.bits, a.bw, m_tmp3, m_tmp4); b.set_repair(random_bool(), m_tmp4); } return true; @@ -1205,13 +1262,13 @@ namespace bv { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = random_bits(); + a.clear_overflow_bits(m_tmp); while (mul_overflow_on_fixed(b, m_tmp)) { auto i = b.msb(m_tmp); b.set(m_tmp, i, false); } while (true) { a.set_mul(m_tmp2, m_tmp, b.bits); - a.clear_overflow_bits(m_tmp2); if (!add_overflow_on_fixed(e, m_tmp2)) break; auto i = b.msb(m_tmp); @@ -1232,7 +1289,7 @@ namespace bv { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = random_bits(); a.set_sub(m_tmp2, a.bits, e.bits); - mpn.div(m_tmp2.data(), a.nw, m_tmp.data(), a.nw, m_tmp3.data(), m_tmp4.data()); + set_div(m_tmp2, m_tmp, a.bw, m_tmp3, m_tmp4); a.clear_overflow_bits(m_tmp3); b.set_repair(random_bool(), m_tmp3); return true; @@ -1280,6 +1337,94 @@ namespace bv { } } + bool sls_eval::try_repair_rotate_right(bvval const& e, bvval& a, bvval& b, unsigned i) { + if (i == 0) { + rational n; + b.get_value(b.bits, n); + n = mod(b.bw - n, rational(b.bw)); + return try_repair_rotate_left(e, a, n.get_unsigned()); + } + else { + SASSERT(i == 1); + unsigned sh = m_rand(b.bw); + b.set(m_tmp, sh); + b.set_repair(random_bool(), m_tmp); + return true; + } + } + + bool sls_eval::try_repair_umul_ovfl(bool e, bvval& a, bvval& b, unsigned i) { + if (e) { + // maximize + if (i == 0) { + a.max_feasible(m_tmp); + a.set_repair(false, m_tmp); + } + else { + b.max_feasible(m_tmp); + b.set_repair(false, m_tmp); + } + } + else { + // minimize + if (i == 0) { + a.min_feasible(m_tmp); + a.set_repair(true, m_tmp); + } + else { + b.min_feasible(m_tmp); + b.set_repair(true, m_tmp); + } + } + return true; + } + + bool sls_eval::try_repair_zero_ext(bvval const& e, bvval& a) { + for (unsigned i = 0; i < e.bw; ++i) + if (!a.get(a.fixed, i)) + a.set(a.bits, i, e.get(e.bits, i)); + return true; + } + + bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i) { + if (i == 0) { + for (unsigned i = 0; i < a.bw; ++i) + if (!a.get(a.fixed, i)) + a.set(a.bits, i, e.get(e.bits, i + b.bw)); + } + else { + for (unsigned i = 0; i < b.bw; ++i) + if (!b.get(b.fixed, i)) + b.set(b.bits, i, e.get(e.bits, i)); + } + return true; + } + + bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { + for (unsigned i = 0; i < a.bw; ++i) + if (!a.get(a.fixed, i)) + a.set(a.bits, i, e.get(e.bits, i + lo)); + return true; + } + + void sls_eval::set_div(svector const& a, svector const& b, unsigned bw, + svector& quot, svector& rem) const { + unsigned nw = (bw + 8 * sizeof(digit_t) - 1) / (8 * sizeof(digit_t)); + unsigned bnw = nw; + while (bnw > 1 && b[bnw - 1] == 0) + --bnw; + if (b[bnw-1] == 0) { + for (unsigned i = 0; i < nw; ++i) { + quot[i] = ~0; + rem[i] = 0; + } + quot[nw - 1] = (1 << (bw % (8 * sizeof(digit_t)))) - 1; + } + else { + mpn.div(a.data(), nw, b.data(), bnw, quot.data(), rem.data()); + } + } + void sls_eval::repair_up(expr* e) { if (!is_app(e)) return; diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 70a08283f..6c7a2053d 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -71,6 +71,7 @@ namespace bv { bool try_repair_band(bvval const& e, bvval& a, bvval const& b); bool try_repair_bor(bvval const& e, bvval& a, bvval const& b); bool try_repair_add(bvval const& e, bvval& a, bvval const& b); + bool try_repair_sub(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_mul(bvval const& e, bvval& a, bvval const& b); bool try_repair_bxor(bvval const& e, bvval& a, bvval const& b); bool try_repair_bnot(bvval const& e, bvval& a); @@ -87,12 +88,19 @@ namespace bv { bool try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const; bool try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_rotate_right(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_ule(bool e, bvval& a, svector const& t); bool try_repair_uge(bool e, bvval& a, svector const& t); + bool try_repair_umul_ovfl(bool e, bvval& a, bvval& b, unsigned i); + bool try_repair_zero_ext(bvval const& e, bvval& a); + bool try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_extract(bvval const& e, bvval& a, unsigned lo); void add_p2_1(bvval const& a, svector& t) const; bool add_overflow_on_fixed(bvval const& a, svector const& t); bool mul_overflow_on_fixed(bvval const& a, svector const& t); + void set_div(svector const& a, svector const& b, unsigned nw, + svector& quot, svector& rem) const; digit_t random_bits(); bool random_bool() { return m_rand() % 2 == 0; } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 490557a56..0d51906bf 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -154,6 +154,7 @@ namespace bv { else v.add_range(-b, -a); } + } void sls_fixed::get_offset(expr* e, expr*& x, rational& offset) { diff --git a/src/ast/sls/bv_sls_terms.cpp b/src/ast/sls/bv_sls_terms.cpp index 0a110a7d8..df84075c9 100644 --- a/src/ast/sls/bv_sls_terms.cpp +++ b/src/ast/sls/bv_sls_terms.cpp @@ -119,8 +119,8 @@ namespace bv { expr* sls_terms::mk_sdiv(expr* x, expr* y) { // d = udiv(abs(x), abs(y)) - // y = 0, x > 0 -> 1 - // y = 0, x <= 0 -> -1 + // y = 0, x >= 0 -> -1 + // y = 0, x < 0 -> 1 // x = 0, y != 0 -> 0 // x > 0, y < 0 -> -d // x < 0, y > 0 -> -d @@ -136,7 +136,7 @@ namespace bv { expr* d = bv.mk_bv_udiv(absx, absy); expr* r = m.mk_ite(m.mk_eq(signx, signy), d, bv.mk_bv_neg(d)); r = m.mk_ite(m.mk_eq(z, y), - m.mk_ite(signx, bv.mk_numeral(N - 1, sz), bv.mk_one(sz)), + m.mk_ite(signx, bv.mk_one(sz), bv.mk_numeral(N - 1, sz)), m.mk_ite(m.mk_eq(x, z), z, r)); return r; } diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 75307c667..3bafca7da 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -177,7 +177,7 @@ namespace bv { bool sls_valuation::round_down(svector& dst) const { if (lt(lo, hi)) { - if (lt(lo, hi)) + if (lt(dst, lo)) return false; if (le(hi, dst)) { set(dst, hi); @@ -324,79 +324,90 @@ namespace bv { } SASSERT(!has_overflow(lo)); SASSERT(!has_overflow(hi)); + init_fixed(); } + // + // tighten lo/hi based on fixed bits. + // lo[bit_i] != fixedbit[bit_i] + // let bit_i be most significant bit position of disagreement. + // if fixedbit = 1, lo = 0, increment lo + // if fixedbit = 0, lo = 1, lo := fixed & bits + // (hi-1)[bit_i] != fixedbit[bit_i] + // if fixedbit = 0, hi-1 = 1, set hi-1 := 0, maximize below bit_i + // if fixedbit = 1, hi-1 = 0, hi := fixed & bits + // tighten fixed bits based on lo/hi + // lo + 1 = hi -> set bits = lo + // lo < hi, set most significant bits based on hi + // void sls_valuation::init_fixed() { if (eq(lo, hi)) return; - bool lo_ok = true; - for (unsigned i = 0; i < nw; ++i) - lo_ok &= (0 == (fixed[i] & (bits[i] ^ lo[i]))); - if (!lo_ok) { - svector tmp(nw + 1); - if (get_at_least(lo, tmp)) { - if (lt(lo, hi) && lt(tmp, hi)) - set(lo, tmp); - else if (gt(lo, hi)) - set(lo, tmp); + for (unsigned i = bw; i-- > 0; ) { + if (!get(fixed, i)) + continue; + if (get(bits, i) == get(lo, i)) + continue; + if (get(bits, i)) { + set(lo, i, true); + for (unsigned j = i; j-- > 0; ) + set(lo, j, get(fixed, j) && get(bits, j)); } - else if (gt(lo, hi)) { - svector zero(nw + 1, (unsigned) 0); - if (get_at_least(zero, tmp) && lt(tmp, hi)) - set(lo, tmp); + else { + for (unsigned j = bw; j-- > 0; ) + set(lo, j, get(fixed, j) && get(bits, j)); } + break; } - bool hi_ok = true; svector hi1(nw + 1, (unsigned)0); svector one(nw + 1, (unsigned)0); one[0] = 1; digit_t c; mpn_manager().sub(hi.data(), nw, one.data(), nw, hi1.data(), &c); - for (unsigned i = 0; i < nw; ++i) - hi_ok &= (0 == (fixed[i] & (bits[i] ^ hi1[i]))); - if (!hi_ok) { - svector tmp(nw + 1); - if (get_at_most(hi1, tmp)) { - if (lt(tmp, hi) && (le(lo, tmp) || lt(hi, lo))) { - mpn_manager().add(tmp.data(), nw, one.data(), nw, hi1.data(), nw + 1, &c); - clear_overflow_bits(hi1); - set(hi, hi1); - } + clear_overflow_bits(hi1); + for (unsigned i = bw; i-- > 0; ) { + if (!get(fixed, i)) + continue; + if (get(bits, i) == get(hi1, i)) + continue; + if (get(hi1, i)) { + set(hi1, i, false); + for (unsigned j = i; j-- > 0; ) + set(hi1, j, !get(fixed, j) || get(bits, j)); } - // TODO other cases + else { + for (unsigned j = bw; j-- > 0; ) + set(hi1, j, get(fixed, j) && get(bits, j)); + } + mpn_manager().add(hi1.data(), nw, one.data(), nw, hi.data(), nw + 1, &c); + clear_overflow_bits(hi); + break; } + // set fixed bits based on bounds + auto set_fixed_bit = [&](unsigned i, bool b) { + if (!get(fixed, i)) { + set(fixed, i, true); + set(bits, i, b); + } + }; + // set most significant bits if (lt(lo, hi)) { unsigned i = bw; - for (; i-- > 0; ) { - if (get(hi, i)) - break; - if (!get(fixed, i)) { - set(fixed, i, true); - set(bits, i, false); - } - } - bool is_power_of2 = true; - for (unsigned j = 0; is_power_of2 && j < i; ++j) - is_power_of2 = !get(hi, j); - if (is_power_of2) { - if (!get(fixed, i)) { - set(fixed, i, true); - set(bits, i, false); - } - } + for (; i-- > 0 && !get(hi, i); ) + set_fixed_bit(i, false); + + if (is_power_of2(hi)) + set_fixed_bit(i, false); } - svector tmp(nw + 1, (unsigned)0); - mpn_manager().add(lo.data(), nw, one.data(), nw, tmp.data(), nw + 1, &c); - clear_overflow_bits(tmp); - if (eq(tmp, hi)) { - for (unsigned i = 0; i < bw; ++i) { - if (!get(fixed, i)) { - set(fixed, i, true); - set(bits, i, get(lo, i)); - } - } + + // lo + 1 = hi: then bits = lo + mpn_manager().add(lo.data(), nw, one.data(), nw, hi1.data(), nw + 1, &c); + clear_overflow_bits(hi1); + if (eq(hi1, hi)) { + for (unsigned i = 0; i < bw; ++i) + set_fixed_bit(i, get(lo, i)); } SASSERT(!has_overflow(bits)); } @@ -424,4 +435,11 @@ namespace bv { return ovfl; } + bool sls_valuation::is_power_of2(svector const& src) const { + unsigned c = 0; + for (unsigned i = 0; i < nw; ++i) + c += get_num_1bits(src[i]); + return c == 1; + } + } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 6a5b241b3..ca68cf5a7 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -108,6 +108,8 @@ namespace bv { // most significant bit or bw if src = 0 unsigned msb(svector const& src) const; + bool is_power_of2(svector const& src) const; + // retrieve largest number at or below (above) src which is feasible // with respect to fixed, lo, hi. bool get_at_most(svector const& src, svector& dst) const; @@ -195,6 +197,16 @@ namespace bv { out << " "; for (unsigned i = 0; i < nw; ++i) out << fixed[i]; + + if (!eq(lo, hi)) { + out << " ["; + for (unsigned i = 0; i < nw; ++i) + out << lo[i]; + out << ", "; + for (unsigned i = 0; i < nw; ++i) + out << hi[i]; + out << "["; + } out << std::dec; return out; } diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp index 3b0fd580a..00ac0547c 100644 --- a/src/test/sls_test.cpp +++ b/src/test/sls_test.cpp @@ -30,6 +30,7 @@ namespace bv { es.push_back(e); sls_eval ev(m); ev.init_eval(es, value); + ev.init_fixed(es); th_rewriter rw(m); expr_ref r(e, m); rw(r); @@ -114,6 +115,14 @@ namespace bv { auto e1 = es1.get(i); auto e2 = es2.get(i); auto e3 = es3.get(i); + if (bv.is_bv_sdiv(e1)) + continue; + if (bv.is_bv_srem(e1)) + continue; + if (bv.is_bv_smod(e1)) + continue; + if (is_app_of(e1, bv.get_fid(), OP_BUADD_OVFL)) + continue; check_repair_idx(e1, e2, 0, x); if (is_app(e1) && to_app(e1)->get_num_args() == 2) check_repair_idx(e1, e3, 1, y); @@ -128,22 +137,30 @@ namespace bv { }; expr_ref_vector es(m); bv_util bv(m); - es.push_back(e1); - es.push_back(e2); - sls_eval ev(m); - ev.init_eval(es, value); th_rewriter rw(m); expr_ref r(e1, m); + rw(r); + es.push_back(m.is_false(r) ? m.mk_not(e1) : e1); + es.push_back(m.is_false(r) ? m.mk_not(e2) : e2); + sls_eval ev(m); + ev.init_eval(es, value); + ev.init_fixed(es); + if (m.is_bool(e1)) { + SASSERT(m.is_true(r) || m.is_false(r)); auto val = m.is_true(r); auto val2 = ev.bval0(e2); if (val != val2) { ev.set(e2, val); auto rep1 = ev.try_repair(to_app(e2), idx); if (!rep1) { - verbose_stream() << "Not repaired " << mk_pp(e2, m) << "\n"; + verbose_stream() << "Not repaired " << mk_pp(e2, m) << " r: " << r << "\n"; } - SASSERT(rep1); + auto val3 = ev.bval0(e2); + if (val3 != val) { + verbose_stream() << "Repaired but not corrected " << mk_pp(e2, m) << "\n"; + } + //SASSERT(rep1); } } if (bv.is_bv(e1)) { @@ -155,7 +172,11 @@ namespace bv { if (!rep2) { verbose_stream() << "Not repaired " << mk_pp(e2, m) << "\n"; } - SASSERT(rep2); + auto val3 = ev.wval0(e2); + if (!val3.eq(val1)) { + verbose_stream() << "Repaired but not corrected " << mk_pp(e2, m) << "\n"; + } + //SASSERT(rep2); } } } @@ -213,5 +234,6 @@ static void test_repair1() { } void tst_sls_test() { + test_repair1(); test_eval1(); } From 4391c909609d0b03d3ad540e66338cc21fd2e43e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Feb 2024 15:32:53 +0700 Subject: [PATCH 16/69] na --- src/ast/sls/bv_sls.cpp | 58 +++++++++++++++++++++++------------ src/ast/sls/bv_sls.h | 5 +-- src/ast/sls/bv_sls_eval.cpp | 42 ++++++++++++++++++++++--- src/ast/sls/bv_sls_eval.h | 1 + src/ast/sls/bv_sls_fixed.cpp | 5 +-- src/ast/sls/sls_stats.h | 7 +++-- src/ast/sls/sls_valuation.cpp | 1 + src/ast/sls/sls_valuation.h | 23 +++++++++----- src/tactic/sls/sls_tactic.cpp | 40 +++++++++++++----------- 9 files changed, 126 insertions(+), 56 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 0b136d390..7476c56e9 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -21,6 +21,7 @@ Author: #include "ast/sls/bv_sls.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" +#include "params/sls_params.hpp" namespace bv { @@ -48,15 +49,17 @@ namespace bv { void sls::reinit_eval() { std::function eval = [&](expr* e, unsigned i) { + auto should_keep = [&]() { + return m_rand() % 100 >= 95; + }; if (m.is_bool(e)) { - if (m_eval.is_fixed0(e)) + if (m_eval.is_fixed0(e) || should_keep()) return m_eval.bval0(e); } else if (bv.is_bv(e)) { auto& w = m_eval.wval0(e); - if (w.get(w.fixed, i)) - return w.get(w.bits, i); - + if (w.get(w.fixed, i) || should_keep()) + return w.get(w.bits, i); } return m_rand() % 2 == 0; }; @@ -77,7 +80,7 @@ namespace bv { unsigned index = m_rand(m_repair_down.size()); e = m_terms.term(m_repair_down.elem_at(index)); } - else if (m_repair_up.empty()) { + else if (!m_repair_up.empty()) { unsigned index = m_rand(m_repair_up.size()); e = m_terms.term(m_repair_up.elem_at(index)); } @@ -85,43 +88,51 @@ namespace bv { } lbool sls::search() { - // init and init_eval were invoked. - unsigned& n = m_stats.m_moves; - n = 0; - for (; n < m_config.m_max_repairs && m.inc(); ++n) { + // init and init_eval were invoked + unsigned n = 0; + for (; n++ < m_config.m_max_repairs && m.inc(); ) { + ++m_stats.m_moves; auto [down, e] = next_to_repair(); if (!e) return l_true; - IF_VERBOSE(20, verbose_stream() << (down ? "d " : "u ") << mk_bounded_pp(e, m, 1) << "\n"); + IF_VERBOSE(20, verbose_stream() << (down ? "d #" : "u #") + << e->get_id() << ": " + << mk_bounded_pp(e, m, 1) << " "; + if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e); + verbose_stream() << "\n"); if (eval_is_correct(e)) { if (down) m_repair_down.remove(e->get_id()); else m_repair_up.remove(e->get_id()); } - else if (down) { - try_repair_down(e); - } + else if (down) + try_repair_down(e); else try_repair_up(e); } return l_undef; } + void sls::trace() { + IF_VERBOSE(2, verbose_stream() + << "(bvsls :restarts " << m_stats.m_restarts + << " :repair-down " << m_repair_down.size() + << " :repair-up " << m_repair_up.size() << ")\n"); + } + lbool sls::operator()() { lbool res = l_undef; + m_stats.reset(); + m_stats.m_restarts = 0; do { - if (!m.inc()) - return l_undef; - res = search(); - if (res != l_undef) - return res; - + break; + trace(); reinit_eval(); } - while (m_stats.m_restarts++ < m_config.m_max_restarts); + while (m.inc() && m_stats.m_restarts++ < m_config.m_max_restarts); return res; } @@ -162,6 +173,8 @@ namespace bv { } bool sls::eval_is_correct(app* e) { + if (!m_eval.can_eval1(e)) + return false; if (m.is_bool(e)) return m_eval.bval0(e) == m_eval.bval1(e); if (bv.is_bv(e)) @@ -208,4 +221,9 @@ namespace bv { terms.reset(); return out; } + + void sls::updt_params(params_ref const& _p) { + sls_params p(_p); + m_config.m_max_restarts = p.max_restarts(); + } } diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index c91838a4c..753cf58ff 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -36,7 +36,7 @@ namespace bv { struct config { unsigned m_max_restarts = 1000; - unsigned m_max_repairs = 100000; + unsigned m_max_repairs = 1000; }; ast_manager& m; @@ -59,6 +59,7 @@ namespace bv { lbool search(); void reinit_eval(); + void trace(); public: sls(ast_manager& m); @@ -85,7 +86,7 @@ namespace bv { */ lbool operator()(); - void updt_params(params_ref const& p) {} + void updt_params(params_ref const& p); void collect_statistics(statistics & st) const { m_stats.collect_statistics(st); } void reset_statistics() { m_stats.reset(); } diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 3f5d0e270..7bd8316b5 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -171,15 +171,41 @@ namespace bv { auto const& vb = wval0(b); return va.eq(vb); } - UNREACHABLE(); - break; + return m.are_equal(a, b); } default: UNREACHABLE(); + break; } UNREACHABLE(); return false; } + + bool sls_eval::can_eval1(app* e) const { + expr* x, * y, * z; + if (m.is_eq(e, x, y)) + return m.is_bool(x) || bv.is_bv(x); + if (m.is_ite(e, x, y, z)) + return m.is_bool(y) || bv.is_bv(y); + if (e->get_family_id() == bv.get_fid()) { + switch (e->get_decl_kind()) { + case OP_BNEG_OVFL: + case OP_BSADD_OVFL: + case OP_BSDIV_OVFL: + case OP_BSMUL_NO_OVFL: + case OP_BSMUL_NO_UDFL: + case OP_BSMUL_OVFL: + return false; + default: + return true; + } + } + if (e->get_family_id() == basic_family_id) + return true; + if (is_uninterp_const(e)) + return m.is_bool(e) || bv.is_bv(e); + return false; + } bool sls_eval::bval1_bv(app* e) const { SASSERT(m.is_bool(e)); @@ -1182,8 +1208,8 @@ namespace bv { if (i == 0) { if (e.is_zero() && a.is_ones(a.fixed) && a.is_ones()) return false; - if (b.is_zero()) - return true; + if (b.is_zero()) + return false; if (!e.is_ones()) { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = ~a.fixed[i] | a.bits[i]; @@ -1215,11 +1241,19 @@ namespace bv { a.set_repair(true, m_tmp3); } else { + if (e.is_one() && a.is_zero()) { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = random_bits(); + a.clear_overflow_bits(m_tmp); + b.set_repair(true, m_tmp); + return true; + } if (e.is_one()) { b.set(m_tmp, a.bits); b.set_repair(true, m_tmp); return true; } + // e * b + r = a // b = (a - r) udiv e // random version of r: diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 6c7a2053d..d2c20e6ad 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -134,6 +134,7 @@ namespace bv { * Retrieve evaluation based on immediate children. */ bool bval1(app* e) const; + bool can_eval1(app* e) const; svector& wval1(app* e) const; diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 0d51906bf..f7cd4c23a 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -11,6 +11,7 @@ Author: --*/ +#include "ast/ast_pp.h" #include "ast/sls/bv_sls_fixed.h" #include "ast/sls/bv_sls_eval.h" @@ -137,12 +138,12 @@ namespace bv { v.add_range(-b, a - b); } else if (!y) { - if (mod(b + 1, rational::power_of_two(bv.get_bv_size(x))) == 1) + if (mod(b + 1, rational::power_of_two(bv.get_bv_size(x))) == 0) return; auto& v = wval0(x); if (!sign) v.add_range(-a, b - a + 1); - else + else v.add_range(b - a + 1, -a); } else if (x == y) { diff --git a/src/ast/sls/sls_stats.h b/src/ast/sls/sls_stats.h index 8599a1f64..9468e9c8d 100644 --- a/src/ast/sls/sls_stats.h +++ b/src/ast/sls/sls_stats.h @@ -35,13 +35,16 @@ namespace bv { st.update("sls restarts", m_restarts); st.update("sls full evals", m_full_evals); st.update("sls incr evals", m_incr_evals); - st.update("sls incr evals/sec", m_incr_evals / seconds); + if (seconds > 0 && m_incr_evals > 0) + st.update("sls incr evals/sec", m_incr_evals / seconds); + if (seconds > 0 && m_moves > 0) + st.update("sls moves/sec", m_moves / seconds); st.update("sls FLIP moves", m_flips); st.update("sls INC moves", m_incs); st.update("sls DEC moves", m_decs); st.update("sls INV moves", m_invs); st.update("sls moves", m_moves); - st.update("sls moves/sec", m_moves / seconds); + } }; diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 3bafca7da..1954b1777 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -296,6 +296,7 @@ namespace bv { h = mod(h, rational::power_of_two(bw)); if (h == l) return; + if (eq(lo, hi)) { set_value(lo, l); set_value(hi, h); diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index ca68cf5a7..bb8100f75 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -192,19 +192,26 @@ namespace bv { std::ostream& display(std::ostream& out) const { out << std::hex; - for (unsigned i = 0; i < nw; ++i) - out << bits[i]; + auto print_bits = [&](svector const& v) { + bool nz = false; + for (unsigned i = nw; i-- > 0;) + if (nz) + out << std::setw(8) << std::setfill('0') << v[i]; + else if (v[i] != 0) + out << v[i], nz = true; + if (!nz) + out << "0"; + }; + + print_bits(bits); out << " "; - for (unsigned i = 0; i < nw; ++i) - out << fixed[i]; + print_bits(fixed); if (!eq(lo, hi)) { out << " ["; - for (unsigned i = 0; i < nw; ++i) - out << lo[i]; + print_bits(lo); out << ", "; - for (unsigned i = 0; i < nw; ++i) - out << hi[i]; + print_bits(hi); out << "["; } out << std::dec; diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index ca3f46bc0..198204d90 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -126,14 +126,15 @@ public: class bv_sls_tactic : public tactic { ast_manager& m; - params_ref m_params; - bv::sls* m_engine; + params_ref m_params; + bv::sls* m_sls; + statistics m_st; public: bv_sls_tactic(ast_manager& _m, params_ref const& p) : m(_m), m_params(p) { - m_engine = alloc(bv::sls, m); + m_sls = alloc(bv::sls, m); } tactic* translate(ast_manager& m) override { @@ -141,14 +142,14 @@ public: } ~bv_sls_tactic() override { - dealloc(m_engine); + dealloc(m_sls); } char const* name() const override { return "bv-sls"; } void updt_params(params_ref const& p) override { m_params.append(p); - m_engine->updt_params(m_params); + m_sls->updt_params(m_params); } void collect_param_descrs(param_descrs& r) override { @@ -162,23 +163,24 @@ public: } for (unsigned i = 0; i < g->size(); i++) - m_engine->assert_expr(g->form(i)); + m_sls->assert_expr(g->form(i)); - m_engine->init(); + m_sls->init(); std::function false_eval = [&](expr* e, unsigned idx) { return false; }; - m_engine->init_eval(false_eval); + m_sls->init_eval(false_eval); - lbool res = m_engine->operator()(); - auto const& stats = m_engine->get_stats(); + lbool res = m_sls->operator()(); + auto const& stats = m_sls->get_stats(); report_tactic_progress("Number of flips:", stats.m_moves); - IF_VERBOSE(0, verbose_stream() << res << "\n"); - IF_VERBOSE(0, m_engine->display(verbose_stream())); - if (res == l_true) { - + IF_VERBOSE(20, verbose_stream() << res << "\n"); + IF_VERBOSE(20, m_sls->display(verbose_stream())); + m_st.reset(); + m_sls->collect_statistics(m_st); + if (res == l_true) { if (g->models_enabled()) { - model_ref mdl = m_engine->get_model(); + model_ref mdl = m_sls->get_model(); mc = model2model_converter(mdl.get()); TRACE("sls_model", mc->display(tout);); } @@ -204,17 +206,19 @@ public: } void cleanup() override { + auto* d = alloc(bv::sls, m); - std::swap(d, m_engine); + std::swap(d, m_sls); dealloc(d); } void collect_statistics(statistics& st) const override { - m_engine->collect_statistics(st); + st.copy(m_st); } void reset_statistics() override { - m_engine->reset_statistics(); + m_sls->reset_statistics(); + m_st.reset(); } }; From 7dc4ce8259b6352445601b8103ab121adcbb1ee2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Feb 2024 01:40:27 -0800 Subject: [PATCH 17/69] use tuned gcd to compute mult inverse --- src/ast/sls/bv_sls.cpp | 3 +- src/ast/sls/bv_sls_eval.cpp | 94 +++++++++++++++++++++++++++++++++-- src/ast/sls/bv_sls_eval.h | 1 + src/ast/sls/sls_valuation.cpp | 21 ++++++-- src/ast/sls/sls_valuation.h | 17 +++++-- 5 files changed, 125 insertions(+), 11 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 7476c56e9..d63bd4f0f 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -50,7 +50,7 @@ namespace bv { void sls::reinit_eval() { std::function eval = [&](expr* e, unsigned i) { auto should_keep = [&]() { - return m_rand() % 100 >= 95; + return m_rand() % 100 >= 98; }; if (m.is_bool(e)) { if (m_eval.is_fixed0(e) || should_keep()) @@ -225,5 +225,6 @@ namespace bv { void sls::updt_params(params_ref const& _p) { sls_params p(_p); m_config.m_max_restarts = p.max_restarts(); + m_rand.set_seed(p.random_seed()); } } diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 7bd8316b5..c01acf88a 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -96,6 +96,11 @@ namespace bv { m_tmp4.push_back(0); m_zero.push_back(0); m_one.push_back(0); + m_a.push_back(0); + m_b.push_back(0); + m_nexta.push_back(0); + m_nextb.push_back(0); + m_aux.push_back(0); m_minus_one.push_back(~0); m_one[0] = 1; } @@ -1011,17 +1016,98 @@ namespace bv { } return false; } + + unsigned parity_e = e.parity(e.bits); + unsigned parity_b = b.parity(b.bits); + +#if 1 + + auto& x = m_tmp; + auto& y = m_tmp2; + auto& quot = m_tmp3; + auto& rem = m_tmp4; + auto& ta = m_a; + auto& tb = m_b; + auto& nexta = m_nexta; + auto& nextb = m_nextb; + auto& aux = m_aux; + + + // x*ta + y*tb = x + b.get(y); + if (parity_b > 0) + b.shift_right(y, parity_b); + y[a.nw] = 0; + a.nw = a.nw + 1; + a.bw = 8 * sizeof(digit_t) * a.nw; + // x = 2 ^ b.bw + a.set_zero(x); + a.set(x, b.bw, true); + + a.set_one(ta); + a.set_zero(tb); + a.set_zero(nexta); + a.set_one(nextb); + + rem.reserve(2 * a.nw); + SASSERT(a.le(y, x)); + while (a.gt(y, m_zero)) { + SASSERT(a.le(y, x)); + set_div(x, y, a.bw, quot, rem); // quot, rem := quot_rem(x, y) + SASSERT(a.le(rem, y)); + a.set(x, y); // x := y + a.set(y, rem); // y := rem + a.set(aux, nexta); // aux := nexta + a.set_mul(rem, quot, nexta, false); + a.set_sub(nexta, ta, rem); // nexta := ta - quot*nexta + a.set(ta, aux); // ta := aux + a.set(aux, nextb); // aux := nextb + a.set_mul(rem, quot, nextb, false); + a.set_sub(nextb, tb, rem); // nextb := tb - quot*nextb + a.set(tb, aux); // tb := aux + } + + a.bw = b.bw; + a.nw = b.nw; + // x*a + y*b = 1 + +#if Z3DEBUG + b.get(y); + if (parity_b > 0) + b.shift_right(y, parity_b); + a.set_mul(m_tmp, tb, y); +#if 0 + for (unsigned i = a.nw; i-- > 0; ) + verbose_stream() << tb[i]; + verbose_stream() << "\n"; + for (unsigned i = a.nw; i-- > 0; ) + verbose_stream() << y[i]; + verbose_stream() << "\n"; + for (unsigned i = a.nw; i-- > 0; ) + verbose_stream() << m_tmp[i]; + verbose_stream() << "\n"; +#endif + SASSERT(b.is_one(m_tmp)); +#endif + e.get(m_tmp2); + if (parity_e > 0 && parity_b > 0) + b.shift_right(m_tmp2, std::min(parity_b, parity_e)); + a.set_mul(m_tmp, tb, m_tmp2); + a.set_repair(random_bool(), m_tmp); + +#else + rational ne, nb; e.get_value(e.bits, ne); b.get_value(b.bits, nb); - unsigned parity_e = e.parity(e.bits); - unsigned parity_b = b.parity(b.bits); + if (parity_b > 0) ne /= rational::power_of_two(std::min(parity_b, parity_e)); auto inv_b = nb.pseudo_inverse(b.bw); rational na = mod(inv_b * ne, rational::power_of_two(a.bw)); a.set_value(m_tmp, na); a.set_repair(random_bool(), m_tmp); +#endif return true; } @@ -1454,7 +1540,9 @@ namespace bv { } quot[nw - 1] = (1 << (bw % (8 * sizeof(digit_t)))) - 1; } - else { + else { + for (unsigned i = 0; i < nw; ++i) + rem[i] = quot[i] = 0; mpn.div(a.data(), nw, b.data(), bnw, quot.data(), rem.data()); } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index d2c20e6ad..bdd6db0ed 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -40,6 +40,7 @@ namespace bv { bool_vector m_fixed; // expr-id -> is Boolean fixed mutable svector m_tmp, m_tmp2, m_tmp3, m_tmp4, m_zero, m_one, m_minus_one; + svector m_a, m_b, m_nextb, m_nexta, m_aux; using bvval = sls_valuation; diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 1954b1777..db977cc2e 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -291,6 +291,15 @@ namespace bv { return value; } + void sls_valuation::shift_right(svector& out, unsigned shift) const { + SASSERT(shift < bw); + unsigned n = shift / (8 * sizeof(digit_t)); + unsigned s = shift % (8 * sizeof(digit_t)); + for (unsigned i = 0; i < bw; ++i) + set(out, i, i + shift < bw ? get(bits, i + shift) : false); + SASSERT(!has_overflow(out)); + } + void sls_valuation::add_range(rational l, rational h) { l = mod(l, rational::power_of_two(bw)); h = mod(h, rational::power_of_two(bw)); @@ -427,11 +436,15 @@ namespace bv { return ovfl; } - bool sls_valuation::set_mul(svector& out, svector const& a, svector const& b) const { + bool sls_valuation::set_mul(svector& out, svector const& a, svector const& b, bool check_overflow) const { mpn_manager().mul(a.data(), nw, b.data(), nw, out.data()); - bool ovfl = has_overflow(out); - for (unsigned i = nw; i < 2 * nw; ++i) - ovfl |= out[i] != 0; + + bool ovfl = false; + if (check_overflow) { + ovfl = has_overflow(out); + for (unsigned i = nw; i < 2 * nw; ++i) + ovfl |= out[i] != 0; + } clear_overflow_bits(out); return ovfl; } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index bb8100f75..a1ec5257f 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -131,9 +131,19 @@ namespace bv { clear_overflow_bits(bits); } - void set_zero() { + void set_zero(svector& out) const { for (unsigned i = 0; i < nw; ++i) - bits[i] = 0; + out[i] = 0; + } + + void set_one(svector& out) const { + for (unsigned i = 1; i < nw; ++i) + out[i] = 0; + out[0] = 1; + } + + void set_zero() { + set_zero(bits); } void sub1(svector& out) const { @@ -149,7 +159,8 @@ namespace bv { void set_sub(svector& out, svector const& a, svector const& b) const; bool set_add(svector& out, svector const& a, svector const& b) const; - bool set_mul(svector& out, svector const& a, svector const& b) const; + bool set_mul(svector& out, svector const& a, svector const& b, bool check_overflow = true) const; + void shift_right(svector& out, unsigned shift) const; void set_range(svector& dst, unsigned lo, unsigned hi, bool b) { for (unsigned i = lo; i < hi; ++i) From ab0459e5aa8d2b3389813ce5b656c9355f536951 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Feb 2024 13:38:04 -0800 Subject: [PATCH 18/69] bugfixes --- src/ast/sls/bv_sls.cpp | 37 ++++++++++++++++++++--------------- src/ast/sls/bv_sls.h | 1 + src/ast/sls/bv_sls_eval.cpp | 2 +- src/ast/sls/bv_sls_fixed.cpp | 4 ++-- src/ast/sls/bv_sls_terms.h | 2 ++ src/ast/sls/sls_valuation.cpp | 3 ++- 6 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index d63bd4f0f..7cfd3f78d 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -38,13 +38,22 @@ namespace bv { void sls::init_eval(std::function& eval) { m_eval.init_eval(m_terms.assertions(), eval); + m_eval.init_fixed(m_terms.assertions()); + init_repair(); + } + + void sls::init_repair() { + m_repair_down.reset(); + m_repair_up.reset(); for (auto* e : m_terms.assertions()) { if (!m_eval.bval0(e)) { m_eval.set(e, true); m_repair_down.insert(e->get_id()); } } - m_eval.init_fixed(m_terms.assertions()); + for (app* t : m_terms.terms()) + if (t && !eval_is_correct(t)) + m_repair_down.insert(t->get_id()); } void sls::reinit_eval() { @@ -64,14 +73,7 @@ namespace bv { return m_rand() % 2 == 0; }; m_eval.init_eval(m_terms.assertions(), eval); - m_repair_down.reset(); - m_repair_up.reset(); - for (auto* e : m_terms.assertions()) { - if (!m_eval.bval0(e)) { - m_eval.set(e, true); - m_repair_down.insert(e->get_id()); - } - } + init_repair(); } std::pair sls::next_to_repair() { @@ -95,12 +97,14 @@ namespace bv { auto [down, e] = next_to_repair(); if (!e) return l_true; + bool is_correct = eval_is_correct(e); IF_VERBOSE(20, verbose_stream() << (down ? "d #" : "u #") - << e->get_id() << ": " - << mk_bounded_pp(e, m, 1) << " "; - if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e); - verbose_stream() << "\n"); - if (eval_is_correct(e)) { + << e->get_id() << ": " + << mk_bounded_pp(e, m, 1) << " "; + if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e) << " "; + if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " "; + verbose_stream() << (is_correct?"C":"U") << "\n"); + if (is_correct) { if (down) m_repair_down.remove(e->get_id()); else @@ -185,8 +189,8 @@ namespace bv { model_ref sls::get_model() { model_ref mdl = alloc(model, m); - m_eval.sort_assertions(m_terms.assertions()); - for (expr* e : m_todo) { + auto& terms = m_eval.sort_assertions(m_terms.assertions()); + for (expr* e : terms) { if (!is_uninterp_const(e)) continue; auto f = to_app(e)->get_decl(); @@ -199,6 +203,7 @@ namespace bv { mdl->register_decl(f, bv.mk_numeral(n, v.bw)); } } + terms.reset(); return mdl; } diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index 753cf58ff..e2030986d 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -59,6 +59,7 @@ namespace bv { lbool search(); void reinit_eval(); + void init_repair(); void trace(); public: diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index c01acf88a..3a128bfcd 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -1020,7 +1020,7 @@ namespace bv { unsigned parity_e = e.parity(e.bits); unsigned parity_b = b.parity(b.bits); -#if 1 +#if 0 auto& x = m_tmp; auto& y = m_tmp2; diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index f7cd4c23a..cb82a50dd 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -103,9 +103,9 @@ namespace bv { else if (!sign && m.is_eq(e, s, t)) { if (bv.is_numeral(s, a)) // t - a <= 0 - init_range(t, -a, nullptr, rational(0), !sign); + init_range(t, -a, nullptr, rational(0), false); else if (bv.is_numeral(t, a)) - init_range(s, -a, nullptr, rational(0), !sign); + init_range(s, -a, nullptr, rational(0), false); } else if (bv.is_bit2bool(e, s, idx)) { auto& val = wval0(s); diff --git a/src/ast/sls/bv_sls_terms.h b/src/ast/sls/bv_sls_terms.h index 95d9a508e..2f9aee225 100644 --- a/src/ast/sls/bv_sls_terms.h +++ b/src/ast/sls/bv_sls_terms.h @@ -67,6 +67,8 @@ namespace bv { app* term(unsigned id) const { return m_terms.get(id); } + app_ref_vector const& terms() const { return m_terms; } + bool is_assertion(expr* e) const { return m_assertion_set.contains(e->get_id()); } }; diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index db977cc2e..21e44b3fe 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -243,9 +243,10 @@ namespace bv { void sls_valuation::get_value(svector const& bits, rational& r) const { rational p(1); + r = 0; for (unsigned i = 0; i < nw; ++i) { r += p * rational(bits[i]); - p *= rational::power_of_two(bw); + p *= rational::power_of_two(8*sizeof(digit_t)); } } From d7e419b7ed2ea4df65334767db0ac48ef5ba4424 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Feb 2024 14:14:12 -0800 Subject: [PATCH 19/69] fixes and checks Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 10 ++++++++++ src/ast/sls/bv_sls_eval.cpp | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 7cfd3f78d..d977ff401 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -171,6 +171,7 @@ namespace bv { } else { m_eval.repair_up(e); + SASSERT(eval_is_correct(e)); for (auto p : m_terms.parents(e)) m_repair_up.insert(p->get_id()); } @@ -191,8 +192,17 @@ namespace bv { model_ref mdl = alloc(model, m); auto& terms = m_eval.sort_assertions(m_terms.assertions()); for (expr* e : terms) { + if (!eval_is_correct(to_app(e))) { + verbose_stream() << "missed evaluation #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; + if (bv.is_bv(e)) { + auto const& v0 = m_eval.wval0(e); + auto const& v1 = m_eval.wval1(to_app(e)); + verbose_stream() << v0 << "\n" << v1 << "\n"; + } + } if (!is_uninterp_const(e)) continue; + auto f = to_app(e)->get_decl(); if (m.is_bool(e)) mdl->register_decl(f, m.mk_bool_val(m_eval.bval0(e))); diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 3a128bfcd..0693ce7cc 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -1020,7 +1020,7 @@ namespace bv { unsigned parity_e = e.parity(e.bits); unsigned parity_b = b.parity(b.bits); -#if 0 +#if 1 auto& x = m_tmp; auto& y = m_tmp2; @@ -1521,9 +1521,9 @@ namespace bv { } bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { - for (unsigned i = 0; i < a.bw; ++i) - if (!a.get(a.fixed, i)) - a.set(a.bits, i, e.get(e.bits, i + lo)); + for (unsigned i = 0; i < e.bw; ++i) + if (!a.get(a.fixed, i + lo)) + a.set(a.bits, i + lo, e.get(e.bits, i)); return true; } @@ -1553,6 +1553,6 @@ namespace bv { if (m.is_bool(e)) set(e, bval1(to_app(e))); else if (bv.is_bv(e)) - wval0(e).try_set(wval1(to_app(e))); + wval0(e).set(wval1(to_app(e))); } } From 9cde4f7e05bfedd8e467044206820d91c0588d4d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Feb 2024 20:42:32 -0800 Subject: [PATCH 20/69] bugfixes --- src/ast/sls/bv_sls.cpp | 9 +++---- src/ast/sls/bv_sls_eval.cpp | 46 ++++++++++++++++++++++++------------ src/ast/sls/bv_sls_eval.h | 2 +- src/ast/sls/bv_sls_fixed.cpp | 19 +++++++++++---- src/ast/sls/bv_sls_terms.cpp | 7 ++++++ 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index d977ff401..337532544 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -166,11 +166,12 @@ namespace bv { void sls::try_repair_up(app* e) { m_repair_up.remove(e->get_id()); - if (m_terms.is_assertion(e)) { - m_repair_down.insert(e->get_id()); - } + if (m_terms.is_assertion(e) || !m_eval.repair_up(e)) + m_repair_down.insert(e->get_id()); else { - m_eval.repair_up(e); + if (!eval_is_correct(e)) { + verbose_stream() << "incorrect eval #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; + } SASSERT(eval_is_correct(e)); for (auto p : m_terms.parents(e)) m_repair_up.insert(p->get_id()); diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 0693ce7cc..cc754997f 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -12,6 +12,7 @@ Author: --*/ #include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" #include "ast/sls/bv_sls.h" namespace bv { @@ -178,7 +179,9 @@ namespace bv { } return m.are_equal(a, b); } + case OP_DISTINCT: default: + verbose_stream() << mk_bounded_pp(e, m) << "\n"; UNREACHABLE(); break; } @@ -511,14 +514,16 @@ namespace bv { } case OP_SIGN_EXT: { auto& a = wval0(e->get_arg(0)); - val.set(a.bits); + for (unsigned i = 0; i < a.bw; ++i) + val.set(val.bits, i, a.get(a.bits, i)); bool sign = a.sign(); val.set_range(val.bits, a.bw, val.bw, sign); break; } case OP_ZERO_EXT: { auto& a = wval0(e->get_arg(0)); - val.set(a.bits); + for (unsigned i = 0; i < a.bw; ++i) + val.set(val.bits, i, a.get(a.bits, i)); val.set_range(val.bits, a.bw, val.bw, false); break; } @@ -1268,6 +1273,7 @@ namespace bv { a.set(m_tmp, i, e.get(e.bits, i - sh)); for (unsigned i = 0; i < sh; ++i) a.set(m_tmp, i, a.get(a.bits, i)); + a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } } @@ -1500,7 +1506,7 @@ namespace bv { } bool sls_eval::try_repair_zero_ext(bvval const& e, bvval& a) { - for (unsigned i = 0; i < e.bw; ++i) + for (unsigned i = 0; i < a.bw; ++i) if (!a.get(a.fixed, i)) a.set(a.bits, i, e.get(e.bits, i)); return true; @@ -1509,21 +1515,25 @@ namespace bv { bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { for (unsigned i = 0; i < a.bw; ++i) - if (!a.get(a.fixed, i)) - a.set(a.bits, i, e.get(e.bits, i + b.bw)); + a.set(m_tmp, i, e.get(e.bits, i + b.bw)); + a.clear_overflow_bits(m_tmp); + a.set_repair(random_bool(), m_tmp); } else { for (unsigned i = 0; i < b.bw; ++i) - if (!b.get(b.fixed, i)) - b.set(b.bits, i, e.get(e.bits, i)); + b.set(m_tmp, i, e.get(e.bits, i)); + b.clear_overflow_bits(m_tmp); + b.set_repair(random_bool(), m_tmp); } return true; } bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { for (unsigned i = 0; i < e.bw; ++i) - if (!a.get(a.fixed, i + lo)) - a.set(a.bits, i + lo, e.get(e.bits, i)); + if (a.get(a.fixed, i + lo) && a.get(a.bits, i + lo) != e.get(e.bits, i)) + return false; + for (unsigned i = 0; i < e.bw; ++i) + a.set(a.bits, i + lo, e.get(e.bits, i)); return true; } @@ -1547,12 +1557,18 @@ namespace bv { } } - void sls_eval::repair_up(expr* e) { + bool sls_eval::repair_up(expr* e) { if (!is_app(e)) - return; - if (m.is_bool(e)) - set(e, bval1(to_app(e))); - else if (bv.is_bv(e)) - wval0(e).set(wval1(to_app(e))); + return false; + if (m.is_bool(e)) { + auto b = bval1(to_app(e)); + if (is_fixed0(e)) + return b == bval0(e); + m_eval[e->get_id()] = b; + return true; + } + if (bv.is_bv(e)) + return wval0(e).try_set(wval1(to_app(e))); + return false; } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index bdd6db0ed..ad9a06fb5 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -156,6 +156,6 @@ namespace bv { /* * Propagate repair up to parent */ - void repair_up(expr* e); + bool repair_up(expr* e); }; } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index cb82a50dd..2423ad680 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -12,6 +12,7 @@ Author: --*/ #include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" #include "ast/sls/bv_sls_fixed.h" #include "ast/sls/bv_sls_eval.h" @@ -138,6 +139,7 @@ namespace bv { v.add_range(-b, a - b); } else if (!y) { + if (mod(b + 1, rational::power_of_two(bv.get_bv_size(x))) == 0) return; auto& v = wval0(x); @@ -300,21 +302,28 @@ namespace bv { if (j > 0 && k > 0) { - for (unsigned i = 0; i < std::min(k, j); ++i) + for (unsigned i = 0; i < std::min(k, j); ++i) { + SASSERT(!v.get(v.bits, i)); v.set(v.fixed, i, true); + } } // lower zj + jk bits are 0 if (zk > 0 || zj > 0) { - for (unsigned i = 0; i < zk + zj; ++i) + for (unsigned i = 0; i < zk + zj; ++i) { + SASSERT(!v.get(v.bits, i)); v.set(v.fixed, i, true); + } } // upper bits are 0, if enough high order bits of a, b are 0. - if (hzj < v.bw && hzk < v.bw && hzj + hzk > v.bw) { + // TODO - buggy + if (false && hzj < v.bw && hzk < v.bw && hzj + hzk > v.bw) { hzj = v.bw - hzj; hzk = v.bw - hzk; - for (unsigned i = hzj + hzk - 1; i < v.bw; ++i) + for (unsigned i = hzj + hzk - 1; i < v.bw; ++i) { + SASSERT(!v.get(v.bits, i)); v.set(v.fixed, i, true); - } + } + } break; } case OP_CONCAT: { diff --git a/src/ast/sls/bv_sls_terms.cpp b/src/ast/sls/bv_sls_terms.cpp index df84075c9..41ab0bf19 100644 --- a/src/ast/sls/bv_sls_terms.cpp +++ b/src/ast/sls/bv_sls_terms.cpp @@ -99,6 +99,13 @@ namespace bv { else if (bv.is_concat(e)) { FOLD_OP(bv.mk_concat); } + else if (m.is_distinct(e)) { + expr_ref_vector es(m); + for (unsigned i = 0; i < num_args; ++i) + for (unsigned j = i + 1; j < num_args; ++j) + es.push_back(m.mk_not(m.mk_eq(arg(i), arg(j)))); + r = m.mk_and(es); + } else if (bv.is_bv_sdiv(e, x, y) || bv.is_bv_sdiv0(e, x, y) || bv.is_bv_sdivi(e, x, y)) { r = mk_sdiv(x, y); } From cd6382f1c86eb3f785443baca643867a95f629fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Feb 2024 22:38:07 -0800 Subject: [PATCH 21/69] fix alias bug Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls_eval.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index cc754997f..4dbd4b11f 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -1039,6 +1039,7 @@ namespace bv { // x*ta + y*tb = x + auto bw = a.bw; b.get(y); if (parity_b > 0) b.shift_right(y, parity_b); @@ -1047,7 +1048,7 @@ namespace bv { a.bw = 8 * sizeof(digit_t) * a.nw; // x = 2 ^ b.bw a.set_zero(x); - a.set(x, b.bw, true); + a.set(x, bw, true); a.set_one(ta); a.set_zero(tb); @@ -1072,8 +1073,8 @@ namespace bv { a.set(tb, aux); // tb := aux } - a.bw = b.bw; - a.nw = b.nw; + a.bw = bw; + a.nw = a.nw - 1; // x*a + y*b = 1 #if Z3DEBUG From 659e384ee716d3d9f70e7730684141b05439950d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 02:11:53 -0800 Subject: [PATCH 22/69] bugfixes Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls_eval.cpp | 2 ++ src/ast/sls/bv_sls_terms.cpp | 23 +++++++++++++---------- src/ast/sls/bv_sls_terms.h | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 4dbd4b11f..f64326d22 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -429,6 +429,8 @@ namespace bv { break; } case OP_CONCAT: { + if (e->get_num_args() != 2) + verbose_stream() << mk_bounded_pp(e, m) << "\n"; SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); diff --git a/src/ast/sls/bv_sls_terms.cpp b/src/ast/sls/bv_sls_terms.cpp index 41ab0bf19..8702c3c48 100644 --- a/src/ast/sls/bv_sls_terms.cpp +++ b/src/ast/sls/bv_sls_terms.cpp @@ -18,6 +18,7 @@ Author: --*/ +#include "ast/ast_ll_pp.h" #include "ast/sls/bv_sls.h" namespace bv { @@ -60,13 +61,15 @@ namespace bv { } void sls_terms::ensure_binary_core(expr* e) { + if (m_translated.get(e->get_id(), nullptr)) + return; + app* a = to_app(e); auto arg = [&](unsigned i) { return m_translated.get(a->get_arg(i)->get_id()); }; unsigned num_args = a->get_num_args(); expr_ref r(m); - expr* x, * y; #define FOLD_OP(oper) \ r = arg(0); \ for (unsigned i = 1; i < num_args; ++i)\ @@ -106,20 +109,20 @@ namespace bv { es.push_back(m.mk_not(m.mk_eq(arg(i), arg(j)))); r = m.mk_and(es); } - else if (bv.is_bv_sdiv(e, x, y) || bv.is_bv_sdiv0(e, x, y) || bv.is_bv_sdivi(e, x, y)) { - r = mk_sdiv(x, y); + else if (bv.is_bv_sdiv(e) || bv.is_bv_sdiv0(e) || bv.is_bv_sdivi(e)) { + r = mk_sdiv(arg(0), arg(1)); } - else if (bv.is_bv_smod(e, x, y) || bv.is_bv_smod0(e, x, y) || bv.is_bv_smodi(e, x, y)) { - r = mk_smod(x, y); + else if (bv.is_bv_smod(e) || bv.is_bv_smod0(e) || bv.is_bv_smodi(e)) { + r = mk_smod(arg(0), arg(1)); } - else if (bv.is_bv_srem(e, x, y) || bv.is_bv_srem0(e, x, y) || bv.is_bv_sremi(e, x, y)) { - r = mk_srem(x, y); + else if (bv.is_bv_srem(e) || bv.is_bv_srem0(e) || bv.is_bv_sremi(e)) { + r = mk_srem(arg(0), arg(1)); } else { for (unsigned i = 0; i < num_args; ++i) - m_todo.push_back(arg(i)); - r = m.mk_app(a->get_decl(), num_args, m_todo.data()); - m_todo.reset(); + m_args.push_back(arg(i)); + r = m.mk_app(a->get_decl(), num_args, m_args.data()); + m_args.reset(); } m_translated.setx(e->get_id(), r); } diff --git a/src/ast/sls/bv_sls_terms.h b/src/ast/sls/bv_sls_terms.h index 2f9aee225..3baffc78e 100644 --- a/src/ast/sls/bv_sls_terms.h +++ b/src/ast/sls/bv_sls_terms.h @@ -31,7 +31,7 @@ namespace bv { class sls_terms { ast_manager& m; bv_util bv; - ptr_vector m_todo; + ptr_vector m_todo, m_args; expr_ref_vector m_assertions, m_pinned, m_translated; app_ref_vector m_terms; vector> m_parents; From cf72a916f8d7c8703aa45605588c0be387c3ec26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 14:11:11 -0800 Subject: [PATCH 23/69] bugfixes, adding plugin solver --- src/ast/sls/bv_sls.cpp | 4 +- src/ast/sls/bv_sls_eval.cpp | 15 +++----- src/ast/sls/bv_sls_eval.h | 4 +- src/ast/sls/sls_valuation.h | 3 +- src/sat/smt/CMakeLists.txt | 1 + src/sat/smt/sls_solver.cpp | 74 +++++++++++++++++++++++++++++++++++++ src/sat/smt/sls_solver.h | 59 +++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 src/sat/smt/sls_solver.cpp create mode 100644 src/sat/smt/sls_solver.h diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 337532544..d2f979277 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -91,7 +91,7 @@ namespace bv { lbool sls::search() { // init and init_eval were invoked - unsigned n = 0; + unsigned n = 0; for (; n++ < m_config.m_max_repairs && m.inc(); ) { ++m_stats.m_moves; auto [down, e] = next_to_repair(); @@ -164,7 +164,7 @@ namespace bv { return was_repaired; } - void sls::try_repair_up(app* e) { + void sls::try_repair_up(app* e) { m_repair_up.remove(e->get_id()); if (m_terms.is_assertion(e) || !m_eval.repair_up(e)) m_repair_down.insert(e->get_id()); diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index f64326d22..0e2ecc768 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -130,7 +130,7 @@ namespace bv { void sls_eval::init_eval_bv(app* e) { if (bv.is_bv(e)) { auto& v = wval0(e); - v.set(wval1(e)); + v.set(wval1(e).bits); } else if (m.is_bool(e)) m_eval.setx(e->get_id(), bval1_bv(e), false); @@ -299,10 +299,10 @@ namespace bv { return bval0(e); } - svector& sls_eval::wval1(app* e) const { + sls_valuation& sls_eval::wval1(app* e) const { auto& val = *m_values1[e->get_id()]; wval1(e, val); - return val.bits; + return val; } void sls_eval::wval1(app* e, sls_valuation& val) const { @@ -429,8 +429,6 @@ namespace bv { break; } case OP_CONCAT: { - if (e->get_num_args() != 2) - verbose_stream() << mk_bounded_pp(e, m) << "\n"; SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); @@ -1005,8 +1003,8 @@ namespace bv { } else { // b := a - e - a.set_sub(m_tmp, a.bits, e.bits); - a.set_repair(random_bool(), m_tmp); + b.set_sub(m_tmp, a.bits, e.bits); + b.set_repair(random_bool(), m_tmp); } return true; } @@ -1186,7 +1184,6 @@ namespace bv { if (a.is_zero(m_tmp2)) return false; if (!a.get_at_least(m_tmp2, m_tmp)) { - verbose_stream() << "could not get at least\n"; return false; } } @@ -1571,7 +1568,7 @@ namespace bv { return true; } if (bv.is_bv(e)) - return wval0(e).try_set(wval1(to_app(e))); + return wval0(e).try_set(wval1(to_app(e)).bits); return false; } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index ad9a06fb5..3c8025fe7 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -136,8 +136,8 @@ namespace bv { */ bool bval1(app* e) const; bool can_eval1(app* e) const; - - svector& wval1(app* e) const; + + sls_valuation& wval1(app* e) const; /** * Override evaluaton. diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index a1ec5257f..0a020c290 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -202,6 +202,7 @@ namespace bv { } std::ostream& display(std::ostream& out) const { + out << "V:"; out << std::hex; auto print_bits = [&](svector const& v) { bool nz = false; @@ -215,7 +216,7 @@ namespace bv { }; print_bits(bits); - out << " "; + out << " fix:"; print_bits(fixed); if (!eq(lo, hi)) { diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index e5d35a4f9..7747b65cb 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -46,6 +46,7 @@ z3_add_component(sat_smt q_solver.cpp recfun_solver.cpp sat_th.cpp + sls_solver.cpp specrel_solver.cpp tseitin_theory_checker.cpp user_solver.cpp diff --git a/src/sat/smt/sls_solver.cpp b/src/sat/smt/sls_solver.cpp new file mode 100644 index 000000000..1466b1b41 --- /dev/null +++ b/src/sat/smt/sls_solver.cpp @@ -0,0 +1,74 @@ +/*++ +Copyright (c) 2020 Microsoft Corporation + +Module Name: + + sls_solver + +Abstract: + + Interface to Concurrent SLS solver + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-21 + +--*/ + +#include "sat/smt/sls_solver.h" +#include "sat/smt/euf_solver.h" +#include "ast/sls/bv_sls.h" + + +namespace sls { + + solver::solver(euf::solver& ctx): + th_euf_solver(ctx, symbol("sls"), ctx.get_manager().mk_family_id("sls")) {} + + solver::~solver() { + if (m_rlimit) { + m_rlimit->cancel(); + m_thread.join(); + } + } + + void solver::push_core() { + if (s().scope_lvl() == s().search_lvl() + 1) + init_local_search(); + } + + void solver::pop_core(unsigned n) { + if (s().scope_lvl() - n <= s().search_lvl()) + sample_local_search(); + } + + void solver::simplify() { + + } + + + void solver::init_local_search() { + if (m_rlimit) { + m_rlimit->cancel(); + m_thread.join(); + } + // set up state for local search solver here + auto* bvsls = alloc(bv::sls, m); + // walk clauses, add them + // walk trail stack until search level, add units + // encapsulate bvsls within the arguments of run-local-search. + // ensure bvsls does not touch ast-manager. + m_thread = std::thread([this]() { run_local_search(*this); }); + m_rlimit = alloc(reslimit); + m_rlimit->push_child(&s().rlimit()); + } + + void solver::sample_local_search() { + + } + + void solver::run_local_search(solver& s) { + + } + +} diff --git a/src/sat/smt/sls_solver.h b/src/sat/smt/sls_solver.h new file mode 100644 index 000000000..2a8f07c0b --- /dev/null +++ b/src/sat/smt/sls_solver.h @@ -0,0 +1,59 @@ +/*++ +Copyright (c) 2020 Microsoft Corporation + +Module Name: + + sls_solver + +Abstract: + + Interface to Concurrent SLS solver + +Author: + + Nikolaj Bjorner (nbjorner) 2024-02-21 + +--*/ +#pragma once + +#include "sat/smt/sat_th.h" +#include "util/rlimit.h" + +namespace euf { + class solver; +} + +namespace sls { + + class solver : public euf::th_euf_solver { + std::atomic m_result; + std::atomic m_completed; + std::thread m_thread; + scoped_ptr m_rlimit; + + void run_local_search(solver& s); + void init_local_search(); + void sample_local_search(); + public: + solver(euf::solver& ctx); + ~solver(); + + void push_core() override; + void pop_core(unsigned n) override; + void simplify() override; + + sat::literal internalize(expr* e, bool sign, bool root) override { UNREACHABLE(); return sat::null_literal; } + void internalize(expr* e) override { UNREACHABLE(); } + th_solver* clone(euf::solver& ctx) override { return alloc(solver, ctx); } + + + bool unit_propagate() override { return false; } + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override { UNREACHABLE(); } + sat::check_result check() override { return sat::check_result::CR_DONE; } + std::ostream & display(std::ostream & out) const override { return out; } + std::ostream & display_justification(std::ostream & out, sat::ext_justification_idx idx) const override { UNREACHABLE(); return out; } + std::ostream & display_constraint(std::ostream & out, sat::ext_constraint_idx idx) const override { UNREACHABLE(); return out; } + + }; + +} From b14499f2301cba4c47e7d8574ad094b148dc0282 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 19:29:21 -0800 Subject: [PATCH 24/69] prepare for sls experiment Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.h | 2 + src/sat/smt/sls_solver.cpp | 80 ++++++++++++++++++++++++++++++++------ src/sat/smt/sls_solver.h | 9 +++-- 3 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index e2030986d..be2e8feed 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -101,5 +101,7 @@ namespace bv { sls_valuation const& wval(expr* e) const { return m_eval.wval0(e); } model_ref get_model(); + + void cancel() { m.limit().cancel(); } }; } diff --git a/src/sat/smt/sls_solver.cpp b/src/sat/smt/sls_solver.cpp index 1466b1b41..8feb9f83e 100644 --- a/src/sat/smt/sls_solver.cpp +++ b/src/sat/smt/sls_solver.cpp @@ -17,7 +17,7 @@ Author: #include "sat/smt/sls_solver.h" #include "sat/smt/euf_solver.h" -#include "ast/sls/bv_sls.h" + namespace sls { @@ -26,8 +26,8 @@ namespace sls { th_euf_solver(ctx, symbol("sls"), ctx.get_manager().mk_family_id("sls")) {} solver::~solver() { - if (m_rlimit) { - m_rlimit->cancel(); + if (m_bvsls) { + m_bvsls->cancel(); m_thread.join(); } } @@ -48,27 +48,83 @@ namespace sls { void solver::init_local_search() { - if (m_rlimit) { - m_rlimit->cancel(); + if (m_bvsls) { + m_bvsls->cancel(); m_thread.join(); + if (m_result == l_true) { + verbose_stream() << "Found model using local search - INIT\n"; + exit(1); + } } // set up state for local search solver here - auto* bvsls = alloc(bv::sls, m); + + m_m = alloc(ast_manager, m); + ast_translation tr(m, *m_m); + + m_completed = false; + m_result = l_undef; + m_bvsls = alloc(bv::sls, *m_m); // walk clauses, add them // walk trail stack until search level, add units // encapsulate bvsls within the arguments of run-local-search. // ensure bvsls does not touch ast-manager. - m_thread = std::thread([this]() { run_local_search(*this); }); - m_rlimit = alloc(reslimit); - m_rlimit->push_child(&s().rlimit()); + + unsigned trail_sz = s().trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { + auto lit = s().trail_literal(i); + if (s().lvl(lit) > s().search_lvl()) + break; + expr_ref fml = literal2expr(lit); + m_bvsls->assert_expr(tr(fml.get())); + } + unsigned num_vars = s().num_vars(); + for (unsigned i = 0; i < 2*num_vars; ++i) { + auto l1 = ~sat::to_literal(i); + auto const& wlist = s().get_wlist(l1); + for (sat::watched const& w : wlist) { + if (!w.is_binary_non_learned_clause()) + continue; + sat::literal l2 = w.get_literal(); + if (l1.index() > l2.index()) + continue; + expr_ref fml(m.mk_or(literal2expr(l1), literal2expr(l2)), m); + m_bvsls->assert_expr(tr(fml.get())); + } + } + for (auto clause : s().clauses()) { + expr_ref_vector cls(m); + for (auto lit : *clause) + cls.push_back(literal2expr(lit)); + expr_ref fml(m.mk_or(cls), m); + m_bvsls->assert_expr(tr(fml.get())); + } + + // use phase assignment from literals? + std::function eval = [&](expr* e, unsigned r) { + return false; + }; + + m_bvsls->init(); + m_bvsls->init_eval(eval); + m_bvsls->updt_params(s().params()); + + m_thread = std::thread([this]() { run_local_search(); }); } void solver::sample_local_search() { - + if (m_completed) { + m_thread.join(); + if (m_result == l_true) { + verbose_stream() << "Found model using local search\n"; + exit(1); + } + } } - void solver::run_local_search(solver& s) { - + void solver::run_local_search() { + lbool r = (*m_bvsls)(); + m_result = r; + m_completed = true; } } diff --git a/src/sat/smt/sls_solver.h b/src/sat/smt/sls_solver.h index 2a8f07c0b..0c466d0cc 100644 --- a/src/sat/smt/sls_solver.h +++ b/src/sat/smt/sls_solver.h @@ -16,8 +16,10 @@ Author: --*/ #pragma once -#include "sat/smt/sat_th.h" #include "util/rlimit.h" +#include "ast/sls/bv_sls.h" +#include "sat/smt/sat_th.h" + namespace euf { class solver; @@ -29,9 +31,10 @@ namespace sls { std::atomic m_result; std::atomic m_completed; std::thread m_thread; - scoped_ptr m_rlimit; + scoped_ptr m_m; + scoped_ptr m_bvsls; - void run_local_search(solver& s); + void run_local_search(); void init_local_search(); void sample_local_search(); public: From 5379fabf9de6856b9ce716589a0c189dd0a6d11a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 19:52:32 -0800 Subject: [PATCH 25/69] include thread Signed-off-by: Nikolaj Bjorner --- src/sat/smt/sls_solver.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/smt/sls_solver.h b/src/sat/smt/sls_solver.h index 0c466d0cc..c473264ac 100644 --- a/src/sat/smt/sls_solver.h +++ b/src/sat/smt/sls_solver.h @@ -16,6 +16,7 @@ Author: --*/ #pragma once +#include #include "util/rlimit.h" #include "ast/sls/bv_sls.h" #include "sat/smt/sat_th.h" From cfa6bd45347ca9b9047dae718e0ca4c91525e9af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 20:33:06 -0800 Subject: [PATCH 26/69] update python build dependencies Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/ast/sls/bv_sls_eval.cpp | 6 +++--- src/ast/sls/sls_valuation.cpp | 8 ++++---- src/ast/sls/sls_valuation.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index d91feea9f..2805cbaf1 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -59,7 +59,7 @@ def init_project_def(): add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model') add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model', 'solver_assertions', 'substitution', 'grobner', 'simplex', 'proofs', 'pattern', 'parser_util', 'fpa', 'lp']) - add_lib('sat_smt', ['sat', 'euf', 'smt', 'tactic', 'solver', 'smt_params', 'bit_blaster', 'fpa', 'mbp', 'normal_forms', 'lp', 'pattern', 'qe_lite'], 'sat/smt') + add_lib('sat_smt', ['sat', 'ast_sls', 'euf', 'smt', 'tactic', 'solver', 'smt_params', 'bit_blaster', 'fpa', 'mbp', 'normal_forms', 'lp', 'pattern', 'qe_lite'], 'sat/smt') add_lib('sat_tactic', ['tactic', 'sat', 'solver', 'sat_smt'], 'sat/tactic') add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv') diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 0e2ecc768..2331572e4 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -983,6 +983,7 @@ namespace bv { bool sls_eval::try_repair_bxor(bvval const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < e.nw; ++i) m_tmp[i] = e.bits[i] ^ b.bits[i]; + a.clear_overflow_bits(m_tmp); a.set_repair(random_bool(), m_tmp); return true; } @@ -1517,15 +1518,14 @@ namespace bv { for (unsigned i = 0; i < a.bw; ++i) a.set(m_tmp, i, e.get(e.bits, i + b.bw)); a.clear_overflow_bits(m_tmp); - a.set_repair(random_bool(), m_tmp); + return a.set_repair(random_bool(), m_tmp); } else { for (unsigned i = 0; i < b.bw; ++i) b.set(m_tmp, i, e.get(e.bits, i)); b.clear_overflow_bits(m_tmp); - b.set_repair(random_bool(), m_tmp); + return b.set_repair(random_bool(), m_tmp); } - return true; } bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 21e44b3fe..15e0aa79a 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -24,7 +24,6 @@ namespace bv { sls_valuation::sls_valuation(unsigned bw): bw(bw) { nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); - unsigned num_bytes = nw * sizeof(digit_t); lo.reserve(nw + 1); hi.reserve(nw + 1); bits.reserve(nw + 1); @@ -192,14 +191,17 @@ namespace bv { return true; } - void sls_valuation::set_repair(bool try_down, svector& dst) { + bool sls_valuation::set_repair(bool try_down, svector& dst) { for (unsigned i = 0; i < nw; ++i) dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & bits[i]); bool ok = try_down ? round_down(dst) : round_up(dst); if (!ok) VERIFY(try_down ? round_up(dst) : round_down(dst)); + if (eq(bits, dst)) + return false; set(bits, dst); SASSERT(!has_overflow(dst)); + return true; } void sls_valuation::min_feasible(svector& out) const { @@ -294,8 +296,6 @@ namespace bv { void sls_valuation::shift_right(svector& out, unsigned shift) const { SASSERT(shift < bw); - unsigned n = shift / (8 * sizeof(digit_t)); - unsigned s = shift % (8 * sizeof(digit_t)); for (unsigned i = 0; i < bw; ++i) set(out, i, i + shift < bw ? get(bits, i + shift) : false); SASSERT(!has_overflow(out)); diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 0a020c290..95cb2e894 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -66,7 +66,7 @@ namespace bv { bool is_ones(svector const& a) const { auto bound = bw % (sizeof(digit_t) * 8) == 0 ? nw : nw - 1; for (unsigned i = 0; i < bound; ++i) - if (a[i] != ~0) + if (a[i] != (a[i] ^ 0)) return false; if (bound < nw) { for (unsigned i = bound * sizeof(digit_t) * 8; i < bw; ++i) @@ -116,7 +116,7 @@ namespace bv { bool get_at_least(svector const& src, svector& dst) const; bool round_up(svector& dst) const; bool round_down(svector& dst) const; - void set_repair(bool try_down, svector& dst); + bool set_repair(bool try_down, svector& dst); bool try_set(svector const& src) { if (!can_set(src)) From acc9c21653f438676fb0294ad1133f3e5f001dc2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2024 10:33:37 -0800 Subject: [PATCH 27/69] move to hide bits Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 26 ++-- src/ast/sls/bv_sls_eval.cpp | 274 +++++++++++++++++----------------- src/ast/sls/bv_sls_eval.h | 5 +- src/ast/sls/bv_sls_fixed.cpp | 37 +++-- src/ast/sls/sls_valuation.cpp | 44 +++--- src/ast/sls/sls_valuation.h | 87 ++++++----- 6 files changed, 253 insertions(+), 220 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index d2f979277..35f014773 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -68,7 +68,7 @@ namespace bv { else if (bv.is_bv(e)) { auto& w = m_eval.wval0(e); if (w.get(w.fixed, i) || should_keep()) - return w.get(w.bits, i); + return w.get_bit(i); } return m_rand() % 2 == 0; }; @@ -98,22 +98,24 @@ namespace bv { if (!e) return l_true; bool is_correct = eval_is_correct(e); - IF_VERBOSE(20, verbose_stream() << (down ? "d #" : "u #") - << e->get_id() << ": " - << mk_bounded_pp(e, m, 1) << " "; - if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e) << " "; - if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " "; - verbose_stream() << (is_correct?"C":"U") << "\n"); if (is_correct) { if (down) m_repair_down.remove(e->get_id()); else m_repair_up.remove(e->get_id()); } - else if (down) - try_repair_down(e); - else - try_repair_up(e); + else { + IF_VERBOSE(20, verbose_stream() << (down ? "d #" : "u #") + << e->get_id() << ": " + << mk_bounded_pp(e, m, 1) << " "; + if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e) << " " << (m_eval.is_fixed0(e)?"fixed ":" "); + if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " "; + verbose_stream() << "\n"); + if (down) + try_repair_down(e); + else + try_repair_up(e); + } } return l_undef; } @@ -210,7 +212,7 @@ namespace bv { else if (bv.is_bv(e)) { auto const& v = m_eval.wval0(e); rational n; - v.get_value(v.bits, n); + v.get_value(v.bits(), n); mdl->register_decl(f, bv.mk_numeral(n, v.bw)); } } diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 2331572e4..4c5ed57fc 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -39,7 +39,7 @@ namespace bv { if (bv.is_bv(e)) { auto& v = wval0(e); for (unsigned i = 0; i < v.bw; ++i) - v.set(v.bits, i, eval(e, i)); + v.set_bit(i, eval(e, i)); } else if (m.is_bool(e)) m_eval.setx(e->get_id(), eval(e, 0), false); @@ -84,7 +84,7 @@ namespace bv { return false; m_values1.reserve(e->get_id() + 1); m_values0.set(e->get_id(), alloc_valuation(bw)); - m_values1.set(e->get_id(), alloc_valuation(bw)); + m_values1.set(e->get_id(), alloc(sls_pre_valuation, bw)); return true; } @@ -118,9 +118,9 @@ namespace bv { auto& val_th = wval0(e->get_arg(1)); auto& val_el = wval0(e->get_arg(2)); if (bval0(e->get_arg(0))) - val.set(val_th.bits); + val.set(val_th.bits()); else - val.set(val_el.bits); + val.set(val_el.bits()); } else { UNREACHABLE(); @@ -130,7 +130,7 @@ namespace bv { void sls_eval::init_eval_bv(app* e) { if (bv.is_bv(e)) { auto& v = wval0(e); - v.set(wval1(e).bits); + v.set(wval1(e).bits()); } else if (m.is_bool(e)) m_eval.setx(e->get_id(), bval1_bv(e), false); @@ -222,7 +222,7 @@ namespace bv { auto ucompare = [&](std::function const& f) { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - return f(mpn.compare(a.bits.data(), a.nw, b.bits.data(), b.nw)); + return f(mpn.compare(a.bits().data(), a.nw, b.bits().data(), b.nw)); }; // x x + 2^{bw-1} get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - return a.set_mul(m_tmp2, a.bits, b.bits); + return a.set_mul(m_tmp2, a.bits(), b.bits()); }; switch (e->get_decl_kind()) { @@ -263,7 +263,7 @@ namespace bv { unsigned idx; VERIFY(bv.is_bit2bool(e, child, idx)); auto& a = wval0(child); - return a.get(a.bits, idx); + return a.get_bit(idx); } case OP_BUMUL_NO_OVFL: return !umul_overflow(); @@ -273,7 +273,7 @@ namespace bv { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - return a.set_add(m_tmp, a.bits, b.bits); + return a.set_add(m_tmp, a.bits(), b.bits()); } case OP_BNEG_OVFL: case OP_BSADD_OVFL: @@ -305,20 +305,20 @@ namespace bv { return val; } - void sls_eval::wval1(app* e, sls_valuation& val) const { + void sls_eval::wval1(app* e, sls_pre_valuation& val) const { SASSERT(bv.is_bv(e)); if (m.is_ite(e)) { SASSERT(bv.is_bv(e->get_arg(1))); auto& val_th = wval0(e->get_arg(1)); auto& val_el = wval0(e->get_arg(2)); if (bval0(e->get_arg(0))) - val.set(val_th.bits); + val.set(val_th.bits()); else - val.set(val_el.bits); + val.set(val_el.bits()); return; } if (e->get_family_id() == null_family_id) { - val.set(wval0(e).bits); + val.set(wval0(e).bits()); return; } auto set_sdiv = [&]() { @@ -344,12 +344,12 @@ namespace bv { val.set(m_zero); else { if (sign_a) - a.set_sub(m_tmp, m_zero, a.bits); + a.set_sub(m_tmp, m_zero, a.bits()); else a.get(m_tmp); if (sign_b) - b.set_sub(m_tmp2, m_zero, b.bits); + b.set_sub(m_tmp2, m_zero, b.bits()); else b.get(m_tmp2); @@ -357,7 +357,7 @@ namespace bv { if (sign_a == sign_b) val.set(m_tmp3); else - val.set_sub(val.bits, m_zero, m_tmp3); + val.set_sub(val.bits(), m_zero, m_tmp3); } }; @@ -371,7 +371,8 @@ namespace bv { case OP_BV_NUM: { rational n; VERIFY(bv.is_numeral(e, n)); - val.set_value(val.bits, n); + val.set_value(m_tmp, n); + val.set(m_tmp); break; } case OP_BAND: { @@ -379,7 +380,7 @@ namespace bv { auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = a.bits[i] & b.bits[i]; + val.bits()[i] = a.bits()[i] & b.bits()[i]; break; } case OP_BOR: { @@ -387,7 +388,7 @@ namespace bv { auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = a.bits[i] | b.bits[i]; + val.bits()[i] = a.bits()[i] | b.bits()[i]; break; } case OP_BXOR: { @@ -395,7 +396,7 @@ namespace bv { auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = a.bits[i] ^ b.bits[i]; + val.bits()[i] = a.bits()[i] ^ b.bits()[i]; break; } case OP_BNAND: { @@ -403,28 +404,28 @@ namespace bv { auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = ~(a.bits[i] & b.bits[i]); + val.bits()[i] = ~(a.bits()[i] & b.bits()[i]); break; } case OP_BADD: { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - val.set_add(val.bits, a.bits, b.bits); + val.set_add(val.bits(), a.bits(), b.bits()); break; } case OP_BSUB: { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - val.set_sub(val.bits, a.bits, b.bits); + val.set_sub(val.bits(), a.bits(), b.bits()); break; } case OP_BMUL: { SASSERT(e->get_num_args() == 2); auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); - val.set_mul(m_tmp2, a.bits, b.bits); + val.set_mul(m_tmp2, a.bits(), b.bits()); val.set(m_tmp2); break; } @@ -433,9 +434,9 @@ namespace bv { auto const& a = wval0(e->get_arg(0)); auto const& b = wval0(e->get_arg(1)); for (unsigned i = 0; i < b.bw; ++i) - val.set(val.bits, i, b.get(b.bits, i)); + val.set_bit(i, b.get_bit(i)); for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i + b.bw, a.get(a.bits, i)); + val.set_bit(i + b.bw, a.get_bit(i)); break; } case OP_EXTRACT: { @@ -445,86 +446,92 @@ namespace bv { auto const& a = wval0(child); SASSERT(lo <= hi && hi + 1 <= a.bw && hi - lo + 1 == val.bw); for (unsigned i = lo; i <= hi; ++i) - val.set(val.bits, i - lo, a.get(a.bits, i)); + val.set_bit(i - lo, a.get_bit(i)); break; } case OP_BNOT: { auto& a = wval0(e->get_arg(0)); for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = ~a.bits[i]; + val.bits()[i] = ~a.bits()[i]; break; } case OP_BNEG: { auto& a = wval0(e->get_arg(0)); - val.set_sub(val.bits, m_zero, a.bits); + val.set_sub(val.bits(), m_zero, a.bits()); break; } case OP_BIT0: - val.set(val.bits, 0, false); + val.set(val.bits(), 0, false); break; case OP_BIT1: - val.set(val.bits, 0, true); + val.set(val.bits(), 0, true); break; case OP_BSHL: { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - auto sh = b.to_nat(b.bits, b.bw); + auto sh = b.to_nat(b.bits(), b.bw); if (sh == 0) - val.set(a.bits); + val.set(a.bits()); else if (sh >= b.bw) val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, i >= sh && a.get(a.bits, i - sh)); + val.set(val.bits(), i, i >= sh && a.get_bit(i - sh)); } break; } case OP_BLSHR: { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - auto sh = b.to_nat(b.bits, b.bw); + auto sh = b.to_nat(b.bits(), b.bw); if (sh == 0) - val.set(a.bits); + val.set(a.bits()); else if (sh >= b.bw) val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, i + sh < a.bw && a.get(a.bits, i + sh)); + val.set(val.bits(), i, i + sh < a.bw && a.get_bit(i + sh)); } break; } case OP_BASHR: { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - auto sh = b.to_nat(b.bits, b.bw); + auto sh = b.to_nat(b.bits(), b.bw); auto sign = a.sign(); if (sh == 0) - val.set(a.bits); + val.set(a.bits()); else if (sh >= b.bw) { for (unsigned i = 0; i < a.nw; ++i) - val.bits[i] = sign ? ~0 : 0; + m_tmp[i] = sign ? ~0 : 0; + val.set(m_tmp); } else { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = 0; for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, i + sh < a.bw && a.get(a.bits, i + sh)); + val.set(m_tmp, i, i + sh < a.bw && a.get_bit(i + sh)); if (sign) - val.set_range(val.bits, a.bw - sh, a.bw, true); + val.set_range(m_tmp, a.bw - sh, a.bw, true); + val.set(m_tmp); } break; } case OP_SIGN_EXT: { auto& a = wval0(e->get_arg(0)); for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, a.get(a.bits, i)); + val.set(m_tmp, i, a.get_bit(i)); bool sign = a.sign(); - val.set_range(val.bits, a.bw, val.bw, sign); + val.set_range(m_tmp, a.bw, val.bw, sign); + val.set(m_tmp); break; } case OP_ZERO_EXT: { auto& a = wval0(e->get_arg(0)); for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits, i, a.get(a.bits, i)); - val.set_range(val.bits, a.bw, val.bw, false); + val.set(m_tmp, i, a.get_bit(i)); + val.set_range(m_tmp, a.bw, val.bw, false); + val.set(m_tmp); break; } case OP_BUREM: @@ -534,9 +541,9 @@ namespace bv { auto& b = wval0(e->get_arg(1)); if (b.is_zero()) - val.set(a.bits); + val.set(a.bits()); else { - set_div(a.bits, b.bits, b.bw, m_tmp, m_tmp2); + set_div(a.bits(), b.bits(), b.bw, m_tmp, m_tmp2); val.set(m_tmp2); } break; @@ -554,25 +561,25 @@ namespace bv { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); if (b.is_zero()) - val.set(a.bits); + val.set(a.bits()); else { if (a.sign()) - a.set_sub(m_tmp3, m_zero, a.bits); + a.set_sub(m_tmp3, m_zero, a.bits()); else - a.set(m_tmp3, a.bits); + a.set(m_tmp3, a.bits()); if (b.sign()) - b.set_sub(m_tmp4, m_zero, b.bits); + b.set_sub(m_tmp4, m_zero, b.bits()); else - a.set(m_tmp4, b.bits); + a.set(m_tmp4, b.bits()); set_div(m_tmp3, m_tmp4, a.bw, m_tmp, m_tmp2); if (val.is_zero(m_tmp2)) val.set(m_tmp2); else if (a.sign() && b.sign()) - val.set_sub(val.bits, m_zero, m_tmp2); + val.set_sub(val.bits(), m_zero, m_tmp2); else if (a.sign()) - val.set_sub(val.bits, b.bits, m_tmp2); + val.set_sub(val.bits(), b.bits(), m_tmp2); else if (b.sign()) - val.set_add(val.bits, b.bits, m_tmp2); + val.set_add(val.bits(), b.bits(), m_tmp2); else val.set(m_tmp2); } @@ -587,7 +594,7 @@ namespace bv { if (b.is_zero()) val.set(m_minus_one); else { - set_div(a.bits, b.bits, a.bw, m_tmp, m_tmp2); + set_div(a.bits(), b.bits(), a.bw, m_tmp, m_tmp2); val.set(m_tmp); } break; @@ -608,11 +615,11 @@ namespace bv { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); if (b.is_zero()) - val.set(a.bits); + val.set(a.bits()); else { set_sdiv(); - val.set_mul(m_tmp, val.bits, b.bits); - val.set_sub(val.bits, a.bits, m_tmp); + val.set_mul(m_tmp, val.bits(), b.bits()); + val.set_sub(val.bits(), a.bits(), m_tmp); } break; } @@ -629,7 +636,7 @@ namespace bv { case OP_EXT_ROTATE_LEFT: { auto& b = wval0(e->get_arg(1)); rational n; - b.get_value(b.bits, n); + b.get_value(b.bits(), n); n = mod(n, rational(val.bw)); SASSERT(n.is_unsigned()); mk_rotate_left(n.get_unsigned()); @@ -638,7 +645,7 @@ namespace bv { case OP_EXT_ROTATE_RIGHT: { auto& b = wval0(e->get_arg(1)); rational n; - b.get_value(b.bits, n); + b.get_value(b.bits(), n); n = mod(n, rational(val.bw)); SASSERT(n.is_unsigned()); mk_rotate_left(val.bw - n.get_unsigned()); @@ -676,7 +683,7 @@ namespace bv { UNREACHABLE(); break; } - val.clear_overflow_bits(val.bits); + val.clear_overflow_bits(val.bits()); } digit_t sls_eval::random_bits() { @@ -891,7 +898,7 @@ namespace bv { auto & a = wval0(e->get_arg(i)); auto & b = wval0(e->get_arg(1 - i)); if (ev) - return a.try_set(b.bits); + return a.try_set(b.bits()); else { // pick random bit to differ a.get(m_tmp); @@ -899,11 +906,11 @@ namespace bv { for (unsigned idx = 0; idx < a.bw; ++idx) { unsigned j = (idx + start) % a.bw; if (!a.get(a.fixed, j)) { - a.set(m_tmp, idx, !b.get(b.bits, j)); + a.set(m_tmp, idx, !b.get_bit(j)); bool r = a.try_set(m_tmp); if (r) return true; - a.set(m_tmp, j, b.get(b.bits, j)); + a.set(m_tmp, j, b.get_bit(j)); } } // could be due to bounds? @@ -935,7 +942,7 @@ namespace bv { return true; } if (bv.is_bv(e)) - return wval0(child).try_set(wval0(e).bits); + return wval0(child).try_set(wval0(e).bits()); return false; } @@ -963,9 +970,8 @@ namespace bv { bool sls_eval::try_repair_band(bvval const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = (e.bits[i] & ~a.fixed[i]) | (~b.bits[i] & ~a.fixed[i] & random_bits()); - a.set_repair(random_bool(), m_tmp); - return true; + m_tmp[i] = (e.bits()[i] & ~a.fixed[i]) | (~b.bits()[i] & ~a.fixed[i] & random_bits()); + return a.set_repair(random_bool(), m_tmp); } // @@ -975,39 +981,35 @@ namespace bv { // bool sls_eval::try_repair_bor(bvval const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = e.bits[i] & (~b.bits[i] | random_bits()); - a.set_repair(random_bool(), m_tmp); - return true; + m_tmp[i] = e.bits()[i] & (~b.bits()[i] | random_bits()); + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_bxor(bvval const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = e.bits[i] ^ b.bits[i]; + m_tmp[i] = e.bits()[i] ^ b.bits()[i]; a.clear_overflow_bits(m_tmp); - a.set_repair(random_bool(), m_tmp); - return true; + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_add(bvval const& e, bvval& a, bvval const& b) { - a.set_sub(m_tmp, e.bits, b.bits); - a.set_repair(random_bool(), m_tmp); - return true; + a.set_sub(m_tmp, e.bits(), b.bits()); + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_sub(bvval const& e, bvval& a, bvval & b, unsigned i) { if (i == 0) { // e = a - b -> a := e + b - a.set_add(m_tmp, e.bits, b.bits); - a.set_repair(random_bool(), m_tmp); + a.set_add(m_tmp, e.bits(), b.bits()); + return a.set_repair(random_bool(), m_tmp); } else { // b := a - e - b.set_sub(m_tmp, a.bits, e.bits); - b.set_repair(random_bool(), m_tmp); + b.set_sub(m_tmp, a.bits(), e.bits()); + return b.set_repair(random_bool(), m_tmp); } - return true; } /** @@ -1020,11 +1022,12 @@ namespace bv { a.set(m_tmp, 1); return a.try_set(m_tmp); } + verbose_stream() << "cannot repair 0\n"; return false; } - unsigned parity_e = e.parity(e.bits); - unsigned parity_b = b.parity(b.bits); + unsigned parity_e = e.parity(e.bits()); + unsigned parity_b = b.parity(b.bits()); #if 1 @@ -1100,7 +1103,7 @@ namespace bv { if (parity_e > 0 && parity_b > 0) b.shift_right(m_tmp2, std::min(parity_b, parity_e)); a.set_mul(m_tmp, tb, m_tmp2); - a.set_repair(random_bool(), m_tmp); + return a.set_repair(random_bool(), m_tmp); #else @@ -1120,31 +1123,31 @@ namespace bv { bool sls_eval::try_repair_bnot(bvval const& e, bvval& a) { for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = ~e.bits[i]; + m_tmp[i] = ~e.bits()[i]; a.clear_overflow_bits(m_tmp); a.set_repair(random_bool(), m_tmp); return true; } bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { - a.set_sub(m_tmp, m_zero, e.bits); + a.set_sub(m_tmp, m_zero, e.bits()); a.set_repair(random_bool(), m_tmp); return true; } bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { - return try_repair_ule(e, a, b.bits); + return try_repair_ule(e, a, b.bits()); } bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) { - return try_repair_uge(e, a, b.bits); + return try_repair_uge(e, a, b.bits()); } // a <=s b <-> a + p2 <=u b + p2 bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { //add_p2_1(b, m_tmp4); - a.set(m_tmp, b.bits); + a.set(m_tmp, b.bits()); if (e) { a.set_repair(true, m_tmp); } @@ -1156,7 +1159,7 @@ namespace bv { } bool sls_eval::try_repair_sge(bool e, bvval& a, bvval const& b) { - a.set(m_tmp, b.bits); + a.set(m_tmp, b.bits()); if (e) { a.set_repair(false, m_tmp); } @@ -1169,7 +1172,7 @@ namespace bv { void sls_eval::add_p2_1(bvval const& a, svector& t) const { a.set(m_zero, a.bw - 1, true); - a.set_add(t, a.bits, m_zero); + a.set_add(t, a.bits(), m_zero); a.set(m_zero, a.bw - 1, false); a.clear_overflow_bits(t); } @@ -1209,16 +1212,16 @@ namespace bv { } bool sls_eval::try_repair_bit2bool(bvval& a, unsigned idx) { - a.set(m_tmp, a.bits); - a.set(m_tmp, idx, !a.get(a.bits, idx)); + a.set(m_tmp, a.bits()); + a.set(m_tmp, idx, !a.get_bit(idx)); return a.try_set(m_tmp); } bool sls_eval::try_repair_shl(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { - unsigned sh = b.to_nat(b.bits, b.bw); + unsigned sh = b.to_nat(b.bits(), b.bw); if (sh == 0) - return a.try_set(e.bits); + return a.try_set(e.bits()); else if (sh >= b.bw) return false; else { @@ -1229,9 +1232,9 @@ namespace bv { // a[bw - 1: bw - sh] = unchanged // for (unsigned i = 0; i < e.bw - sh; ++i) - e.set(m_tmp, i, e.get(e.bits, sh + i)); + e.set(m_tmp, i, e.get_bit(sh + i)); for (unsigned i = e.bw - sh; i < e.bw; ++i) - e.set(m_tmp, i, e.get(a.bits, i)); + e.set(m_tmp, i, a.get_bit(i)); return a.try_set(m_tmp); } } @@ -1247,19 +1250,19 @@ namespace bv { bool sls_eval::try_repair_ashr(bvval const& e, bvval & a, bvval& b, unsigned i) { if (i == 0) { - unsigned sh = b.to_nat(b.bits, b.bw); + unsigned sh = b.to_nat(b.bits(), b.bw); if (sh == 0) - return a.try_set(e.bits); + return a.try_set(e.bits()); else if (sh >= b.bw) { - if (e.get(e.bits, e.bw - 1)) { - if (!a.get(a.bits, a.bw - 1) && !a.get(a.fixed, a.bw - 1)) - a.set(a.bits, a.bw - 1, true); + if (e.get_bit(e.bw - 1)) { + if (!a.get_bit(a.bw - 1) && !a.get(a.fixed, a.bw - 1)) + a.set_bit(a.bw - 1, true); else return false; } else { - if (a.get(a.bits, a.bw - 1) && !a.get(a.fixed, a.bw - 1)) - a.set(a.bits, a.bw - 1, false); + if (a.get_bit(a.bw - 1) && !a.get(a.fixed, a.bw - 1)) + a.set_bit(a.bw - 1, false); else return false; } @@ -1271,9 +1274,9 @@ namespace bv { // a[sh-1:0] = a[sh-1:0] // ignore sign for (unsigned i = sh; i < a.bw; ++i) - a.set(m_tmp, i, e.get(e.bits, i - sh)); + a.set(m_tmp, i, e.get_bit(i - sh)); for (unsigned i = 0; i < sh; ++i) - a.set(m_tmp, i, a.get(a.bits, i)); + a.set(m_tmp, i, a.get_bit(i)); a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } @@ -1305,20 +1308,20 @@ namespace bv { return false; if (!e.is_ones()) { for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = ~a.fixed[i] | a.bits[i]; + m_tmp[i] = ~a.fixed[i] | a.bits()[i]; a.clear_overflow_bits(m_tmp); - if (a.lt(m_tmp, e.bits)) + if (a.lt(m_tmp, e.bits())) return false; } // e = 1 => a := b if (e.is_one()) { - a.set(m_tmp, b.bits); + a.set(m_tmp, b.bits()); a.set_repair(false, m_tmp); return true; } // b * e + r = a for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = (random_bits() & ~b.fixed[i]) | (b.fixed[i] & b.bits[i]); + m_tmp[i] = (random_bits() & ~b.fixed[i]) | (b.fixed[i] & b.bits()[i]); b.clear_overflow_bits(m_tmp); while (mul_overflow_on_fixed(e, m_tmp)) { auto i = b.msb(m_tmp); @@ -1327,7 +1330,7 @@ namespace bv { for (unsigned i = 0; i < a.nw; ++i) m_tmp2[i] = random_bits(); b.clear_overflow_bits(m_tmp2); - while (b.gt(m_tmp2, b.bits)) + while (b.gt(m_tmp2, b.bits())) b.set(m_tmp2, b.msb(m_tmp2), false); while (a.set_add(m_tmp3, m_tmp, m_tmp2)) b.set(m_tmp2, b.msb(m_tmp2), false); @@ -1342,7 +1345,7 @@ namespace bv { return true; } if (e.is_one()) { - b.set(m_tmp, a.bits); + b.set(m_tmp, a.bits()); b.set_repair(true, m_tmp); return true; } @@ -1354,10 +1357,10 @@ namespace bv { m_tmp[i] = random_bits(); a.clear_overflow_bits(m_tmp); // ensure r <= m - while (a.lt(a.bits, m_tmp)) + while (a.lt(a.bits(), m_tmp)) a.set(m_tmp, a.msb(m_tmp), false); - a.set_sub(m_tmp2, a.bits, m_tmp); - set_div(m_tmp2, e.bits, a.bw, m_tmp3, m_tmp4); + a.set_sub(m_tmp2, a.bits(), m_tmp); + set_div(m_tmp2, e.bits(), a.bw, m_tmp3, m_tmp4); b.set_repair(random_bool(), m_tmp4); } return true; @@ -1377,9 +1380,8 @@ namespace bv { if (i == 0) { if (b.is_zero()) { - a.set(m_tmp, e.bits); - a.set_repair(random_bool(), m_tmp); - return true; + a.set(m_tmp, e.bits()); + return a.set_repair(random_bool(), m_tmp); } // a urem b = e: b*y + e = a // ~Ovfl*(b, y) @@ -1395,13 +1397,13 @@ namespace bv { b.set(m_tmp, i, false); } while (true) { - a.set_mul(m_tmp2, m_tmp, b.bits); + a.set_mul(m_tmp2, m_tmp, b.bits()); if (!add_overflow_on_fixed(e, m_tmp2)) break; auto i = b.msb(m_tmp); b.set(m_tmp, i, false); } - a.set_add(m_tmp3, m_tmp2, e.bits); + a.set_add(m_tmp3, m_tmp2, e.bits()); a.set_repair(random_bool(), m_tmp3); return true; } @@ -1415,7 +1417,7 @@ namespace bv { // lower y as long as y*b overflows with fixed bits in b for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = random_bits(); - a.set_sub(m_tmp2, a.bits, e.bits); + a.set_sub(m_tmp2, a.bits(), e.bits()); set_div(m_tmp2, m_tmp, a.bw, m_tmp3, m_tmp4); a.clear_overflow_bits(m_tmp3); b.set_repair(random_bool(), m_tmp3); @@ -1426,14 +1428,14 @@ namespace bv { bool sls_eval::add_overflow_on_fixed(bvval const& a, svector const& t) { a.set(m_tmp3, m_zero); for (unsigned i = 0; i < a.nw; ++i) - m_tmp3[i] = a.fixed[i] & a.bits[i]; + m_tmp3[i] = a.fixed[i] & a.bits()[i]; return a.set_add(m_tmp4, t, m_tmp3); } bool sls_eval::mul_overflow_on_fixed(bvval const& a, svector const& t) { a.set(m_tmp3, m_zero); for (unsigned i = 0; i < a.nw; ++i) - m_tmp3[i] = a.fixed[i] & a.bits[i]; + m_tmp3[i] = a.fixed[i] & a.bits()[i]; return a.set_mul(m_tmp4, m_tmp3, t); } @@ -1441,9 +1443,9 @@ namespace bv { // a := rotate_right(e, n) n = (a.bw - n) % a.bw; for (unsigned i = a.bw - n; i < a.bw; ++i) - a.set(m_tmp, i + n - a.bw, e.get(e.bits, i)); + a.set(m_tmp, i + n - a.bw, e.get_bit(i)); for (unsigned i = 0; i < a.bw - n; ++i) - a.set(m_tmp, i + n, e.get(e.bits, i)); + a.set(m_tmp, i + n, e.get_bit(i)); a.set_repair(true, m_tmp); return true; } @@ -1451,7 +1453,7 @@ namespace bv { bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { rational n; - b.get_value(b.bits, n); + b.get_value(b.bits(), n); n = mod(n, rational(b.bw)); return try_repair_rotate_left(e, a, n.get_unsigned()); } @@ -1467,7 +1469,7 @@ namespace bv { bool sls_eval::try_repair_rotate_right(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { rational n; - b.get_value(b.bits, n); + b.get_value(b.bits(), n); n = mod(b.bw - n, rational(b.bw)); return try_repair_rotate_left(e, a, n.get_unsigned()); } @@ -1509,20 +1511,20 @@ namespace bv { bool sls_eval::try_repair_zero_ext(bvval const& e, bvval& a) { for (unsigned i = 0; i < a.bw; ++i) if (!a.get(a.fixed, i)) - a.set(a.bits, i, e.get(e.bits, i)); + a.set_bit(i, e.get_bit(i)); return true; } bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { for (unsigned i = 0; i < a.bw; ++i) - a.set(m_tmp, i, e.get(e.bits, i + b.bw)); + a.set(m_tmp, i, e.get_bit(i + b.bw)); a.clear_overflow_bits(m_tmp); return a.set_repair(random_bool(), m_tmp); } else { for (unsigned i = 0; i < b.bw; ++i) - b.set(m_tmp, i, e.get(e.bits, i)); + b.set(m_tmp, i, e.get_bit(i)); b.clear_overflow_bits(m_tmp); return b.set_repair(random_bool(), m_tmp); } @@ -1530,10 +1532,10 @@ namespace bv { bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { for (unsigned i = 0; i < e.bw; ++i) - if (a.get(a.fixed, i + lo) && a.get(a.bits, i + lo) != e.get(e.bits, i)) + if (a.get(a.fixed, i + lo) && a.get_bit(i + lo) != e.get_bit(i)) return false; for (unsigned i = 0; i < e.bw; ++i) - a.set(a.bits, i + lo, e.get(e.bits, i)); + a.set_bit(i + lo, e.get_bit(i)); return true; } @@ -1568,7 +1570,7 @@ namespace bv { return true; } if (bv.is_bv(e)) - return wval0(e).try_set(wval1(to_app(e)).bits); + return wval0(e).try_set(wval1(to_app(e)).bits()); return false; } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 3c8025fe7..4669c24b2 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -35,7 +35,8 @@ namespace bv { ptr_vector m_todo; random_gen m_rand; - scoped_ptr_vector m_values0, m_values1; // expr-id -> bv valuation + scoped_ptr_vector m_values0; // expr-id -> bv valuation + scoped_ptr_vector m_values1; // expr-id -> bv valuation bool_vector m_eval; // expr-id -> boolean valuation bool_vector m_fixed; // expr-id -> is Boolean fixed @@ -108,7 +109,7 @@ namespace bv { sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); } - void wval1(app* e, sls_valuation& val) const; + void wval1(app* e, sls_pre_valuation& val) const; public: sls_eval(ast_manager& m); diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 2423ad680..05d9599c1 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -25,7 +25,7 @@ namespace bv { {} void sls_fixed::init(expr_ref_vector const& es) { - init_ranges(es); + // init_ranges(es); ev.sort_assertions(es); for (expr* e : ev.m_todo) { if (!is_app(e)) @@ -110,7 +110,7 @@ namespace bv { } else if (bv.is_bit2bool(e, s, idx)) { auto& val = wval0(s); - val.set(val.bits, idx, !sign); + val.set_bit(idx, !sign); val.set(val.fixed, idx, true); val.init_fixed(); } @@ -184,7 +184,7 @@ namespace bv { auto& val_th = wval0(e->get_arg(1)); auto& val_el = wval0(e->get_arg(2)); for (unsigned i = 0; i < val.nw; ++i) - val.fixed[i] = val_el.fixed[i] & val_th.fixed[i] & ~(val_el.bits[i] ^ val_th.bits[i]); + val.fixed[i] = val_el.fixed[i] & val_th.fixed[i] & ~(val_el.bits(i) ^ val_th.bits(i)); val.init_fixed(); } } @@ -232,7 +232,7 @@ namespace bv { auto& b = wval0(e->get_arg(1)); // (a.fixed & b.fixed) | (a.fixed & ~a.bits) | (b.fixed & ~b.bits) for (unsigned i = 0; i < a.nw; ++i) - v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & ~a.bits[i]) | (b.fixed[i] & ~b.bits[i]); + v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & ~a.bits(i)) | (b.fixed[i] & ~b.bits(i)); break; } case OP_BOR: { @@ -240,7 +240,7 @@ namespace bv { auto& b = wval0(e->get_arg(1)); // (a.fixed & b.fixed) | (a.fixed & a.bits) | (b.fixed & b.bits) for (unsigned i = 0; i < a.nw; ++i) - v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & a.bits[i]) | (b.fixed[i] & b.bits[i]); + v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & a.bits(i)) | (b.fixed[i] & b.bits(i)); break; } case OP_BXOR: { @@ -264,7 +264,7 @@ namespace bv { if (pfixed && a.get(a.fixed, i) && b.get(b.fixed, i)) v.set(v.fixed, i, true); else if (!pfixed && a.get(a.fixed, i) && b.get(b.fixed, i) && - !a.get(a.bits, i) && !b.get(b.bits, i)) { + !a.get_bit(i) && !b.get_bit(i)) { pfixed = true; v.set(v.fixed, i, false); } @@ -273,6 +273,17 @@ namespace bv { v.set(v.fixed, i, false); } } + rational r, rlo, rhi; + if (bv.is_numeral(e->get_arg(0), r) && !b.eq(b.lo, b.hi)) { + b.get_value(b.lo, rlo); + b.get_value(b.hi, rhi); + v.add_range(r + rlo, r + rhi); + } + if (bv.is_numeral(e->get_arg(1), r) && !a.eq(a.lo, a.hi)) { + a.get_value(a.lo, rlo); + a.get_value(a.hi, rhi); + v.add_range(r + rlo, r + rhi); + } break; } case OP_BMUL: { @@ -288,29 +299,29 @@ namespace bv { if (!b.get(b.fixed, k)) break; for (; zj < v.bw; ++zj) - if (!a.get(a.fixed, zj) || a.get(a.bits, zj)) + if (!a.get(a.fixed, zj) || a.get_bit(zj)) break; for (; zk < v.bw; ++zk) - if (!b.get(b.fixed, zk) || b.get(b.bits, zk)) + if (!b.get(b.fixed, zk) || b.get_bit(zk)) break; for (; hzj < v.bw; ++hzj) - if (!a.get(a.fixed, v.bw - hzj - 1) || a.get(a.bits, v.bw - hzj - 1)) + if (!a.get(a.fixed, v.bw - hzj - 1) || a.get_bit(v.bw - hzj - 1)) break; for (; hzk < v.bw; ++hzk) - if (!b.get(b.fixed, v.bw - hzk - 1) || b.get(b.bits, v.bw - hzk - 1)) + if (!b.get(b.fixed, v.bw - hzk - 1) || b.get_bit(v.bw - hzk - 1)) break; if (j > 0 && k > 0) { for (unsigned i = 0; i < std::min(k, j); ++i) { - SASSERT(!v.get(v.bits, i)); + SASSERT(!v.get_bit(i)); v.set(v.fixed, i, true); } } // lower zj + jk bits are 0 if (zk > 0 || zj > 0) { for (unsigned i = 0; i < zk + zj; ++i) { - SASSERT(!v.get(v.bits, i)); + SASSERT(!v.get_bit(i)); v.set(v.fixed, i, true); } } @@ -320,7 +331,7 @@ namespace bv { hzj = v.bw - hzj; hzk = v.bw - hzk; for (unsigned i = hzj + hzk - 1; i < v.bw; ++i) { - SASSERT(!v.get(v.bits, i)); + SASSERT(!v.get_bit(i)); v.set(v.fixed, i, true); } } diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 15e0aa79a..03daab05b 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -26,11 +26,11 @@ namespace bv { nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); lo.reserve(nw + 1); hi.reserve(nw + 1); - bits.reserve(nw + 1); + m_bits.reserve(nw + 1); fixed.reserve(nw + 1); // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated for (unsigned i = 0; i < nw; ++i) - lo[i] = 0, hi[i] = 0, bits[i] = 0, fixed[i] = 0; + lo[i] = 0, hi[i] = 0, m_bits[i] = 0, fixed[i] = 0; for (unsigned i = bw; i < 8 * sizeof(digit_t) * nw; ++i) set(fixed, i, true); } @@ -103,7 +103,7 @@ namespace bv { bool sls_valuation::get_at_most(svector const& src, svector& dst) const { SASSERT(!has_overflow(src)); for (unsigned i = 0; i < nw; ++i) - dst[i] = src[i] & (~fixed[i] | bits[i]); + dst[i] = src[i] & (~fixed[i] | m_bits[i]); // // If dst < src, then find the most significant @@ -116,7 +116,7 @@ namespace bv { auto mask = (1 << idx) - 1; dst[i] = (~fixed[i] & mask) | dst[i]; for (unsigned j = i; j-- > 0; ) - dst[j] = (~fixed[j] | bits[j]); + dst[j] = (~fixed[j] | m_bits[j]); break; } } @@ -140,7 +140,7 @@ namespace bv { bool sls_valuation::get_at_least(svector const& src, svector& dst) const { SASSERT(!has_overflow(src)); for (unsigned i = 0; i < nw; ++i) - dst[i] = (~fixed[i] & src[i]) | (fixed[i] & bits[i]); + dst[i] = (~fixed[i] & src[i]) | (fixed[i] & m_bits[i]); // // If dst > src, then find the most significant @@ -193,13 +193,13 @@ namespace bv { bool sls_valuation::set_repair(bool try_down, svector& dst) { for (unsigned i = 0; i < nw; ++i) - dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & bits[i]); + dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); bool ok = try_down ? round_down(dst) : round_up(dst); if (!ok) VERIFY(try_down ? round_up(dst) : round_down(dst)); - if (eq(bits, dst)) + if (eq(m_bits, dst)) return false; - set(bits, dst); + set(m_bits, dst); SASSERT(!has_overflow(dst)); return true; } @@ -211,7 +211,7 @@ namespace bv { } else { for (unsigned i = 0; i < nw; ++i) - out[i] = fixed[i] & bits[i]; + out[i] = fixed[i] & m_bits[i]; } SASSERT(!has_overflow(out)); } @@ -224,7 +224,7 @@ namespace bv { } else { for (unsigned i = 0; i < nw; ++i) - out[i] = ~fixed[i] | bits[i]; + out[i] = ~fixed[i] | m_bits[i]; } SASSERT(!has_overflow(out)); } @@ -254,7 +254,7 @@ namespace bv { void sls_valuation::get(svector& dst) const { for (unsigned i = 0; i < nw; ++i) - dst[i] = bits[i]; + dst[i] = m_bits[i]; } void sls_valuation::set1(svector& bits) { @@ -270,7 +270,7 @@ namespace bv { bool sls_valuation::can_set(svector const& new_bits) const { SASSERT(!has_overflow(new_bits)); for (unsigned i = 0; i < nw; ++i) - if (0 != ((new_bits[i] ^ bits[i]) & fixed[i])) + if (0 != ((new_bits[i] ^ m_bits[i]) & fixed[i])) return false; return in_range(new_bits); } @@ -297,7 +297,7 @@ namespace bv { void sls_valuation::shift_right(svector& out, unsigned shift) const { SASSERT(shift < bw); for (unsigned i = 0; i < bw; ++i) - set(out, i, i + shift < bw ? get(bits, i + shift) : false); + set(out, i, i + shift < bw ? get(m_bits, i + shift) : false); SASSERT(!has_overflow(out)); } @@ -357,16 +357,16 @@ namespace bv { for (unsigned i = bw; i-- > 0; ) { if (!get(fixed, i)) continue; - if (get(bits, i) == get(lo, i)) + if (get(m_bits, i) == get(lo, i)) continue; - if (get(bits, i)) { + if (get(m_bits, i)) { set(lo, i, true); for (unsigned j = i; j-- > 0; ) - set(lo, j, get(fixed, j) && get(bits, j)); + set(lo, j, get(fixed, j) && get(m_bits, j)); } else { for (unsigned j = bw; j-- > 0; ) - set(lo, j, get(fixed, j) && get(bits, j)); + set(lo, j, get(fixed, j) && get(m_bits, j)); } break; } @@ -379,16 +379,16 @@ namespace bv { for (unsigned i = bw; i-- > 0; ) { if (!get(fixed, i)) continue; - if (get(bits, i) == get(hi1, i)) + if (get(m_bits, i) == get(hi1, i)) continue; if (get(hi1, i)) { set(hi1, i, false); for (unsigned j = i; j-- > 0; ) - set(hi1, j, !get(fixed, j) || get(bits, j)); + set(hi1, j, !get(fixed, j) || get(m_bits, j)); } else { for (unsigned j = bw; j-- > 0; ) - set(hi1, j, get(fixed, j) && get(bits, j)); + set(hi1, j, get(fixed, j) && get(m_bits, j)); } mpn_manager().add(hi1.data(), nw, one.data(), nw, hi.data(), nw + 1, &c); clear_overflow_bits(hi); @@ -399,7 +399,7 @@ namespace bv { auto set_fixed_bit = [&](unsigned i, bool b) { if (!get(fixed, i)) { set(fixed, i, true); - set(bits, i, b); + set(m_bits, i, b); } }; @@ -420,7 +420,7 @@ namespace bv { for (unsigned i = 0; i < bw; ++i) set_fixed_bit(i, get(lo, i)); } - SASSERT(!has_overflow(bits)); + SASSERT(!has_overflow(m_bits)); } void sls_valuation::set_sub(svector& out, svector const& a, svector const& b) const { diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 95cb2e894..d67c0d6d2 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -12,7 +12,7 @@ Abstract: Author: Nikolaj Bjorner (nbjorner) 2024-02-07 - + --*/ #pragma once @@ -27,42 +27,50 @@ Author: namespace bv { - struct sls_valuation { + class sls_valuation { + protected: + svector m_bits; + public: unsigned bw; // bit-width unsigned nw; // num words - svector lo, hi; // range assignment to bit-vector, as wrap-around interval - svector bits, fixed; // bit assignment and don't care bit + svector lo, hi; // range assignment to bit-vector, as wrap-around interval + svector fixed; // bit assignment and don't care bit sls_valuation(unsigned bw); - + unsigned num_bytes() const { return (bw + 7) / 8; } + digit_t bits(unsigned i) const { return m_bits[i]; } + svector const& bits() const { return m_bits; } + void set_bit(unsigned i, bool v) { set(m_bits, i, v); } + bool get_bit(unsigned i) const { return get(m_bits, i); } + void set_value(svector& bits, rational const& r); void get_value(svector const& bits, rational& r) const; void get(svector& dst) const; void add_range(rational lo, rational hi); void init_fixed(); void set1(svector& bits); - + void clear_overflow_bits(svector& bits) const; - bool in_range(svector const& bits) const; + bool in_range(svector const& bits) const; bool can_set(svector const& bits) const; - bool eq(sls_valuation const& other) const { return eq(other.bits); } + bool eq(sls_valuation const& other) const { return eq(other.m_bits); } - bool eq(svector const& other) const { return eq(other, bits); } + bool eq(svector const& other) const { return eq(other, m_bits); } bool eq(svector const& a, svector const& b) const; bool gt(svector const& a, svector const& b) const; bool lt(svector const& a, svector const& b) const; bool le(svector const& a, svector const& b) const; - bool is_zero() const { return is_zero(bits); } - bool is_zero(svector const& a) const { - for (unsigned i = 0; i < nw; ++i) - if (a[i] != 0) - return false; - return true; + bool is_zero() const { return is_zero(m_bits); } + bool is_zero(svector const& a) const { + for (unsigned i = 0; i < nw; ++i) + if (a[i] != 0) + return false; + return true; } - bool is_ones() const { return is_ones(bits); } + bool is_ones() const { return is_ones(m_bits); } bool is_ones(svector const& a) const { auto bound = bw % (sizeof(digit_t) * 8) == 0 ? nw : nw - 1; for (unsigned i = 0; i < bound; ++i) @@ -76,7 +84,7 @@ namespace bv { return true; } - bool is_one() const { return is_one(bits); } + bool is_one() const { return is_one(m_bits); } bool is_one(svector const& bits) const { if (1 != bits[0]) return false; @@ -86,7 +94,7 @@ namespace bv { return true; } - bool sign() const { return get(bits, bw - 1); } + bool sign() const { return get(m_bits, bw - 1); } bool has_overflow(svector const& bits) const { for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) @@ -96,10 +104,10 @@ namespace bv { } unsigned parity(svector const& bits) const { - for (unsigned i = 0; i < nw; ++i) + for (unsigned i = 0; i < nw; ++i) if (bits[i] != 0) return (8 * sizeof(digit_t) * i) + trailing_zeros(bits[i]); - return bw; + return bw; } void min_feasible(svector& out) const; @@ -127,8 +135,8 @@ namespace bv { void set(svector const& src) { for (unsigned i = nw; i-- > 0; ) - bits[i] = src[i]; - clear_overflow_bits(bits); + m_bits[i] = src[i]; + clear_overflow_bits(m_bits); } void set_zero(svector& out) const { @@ -143,7 +151,7 @@ namespace bv { } void set_zero() { - set_zero(bits); + set_zero(m_bits); } void sub1(svector& out) const { @@ -189,17 +197,7 @@ namespace bv { unsigned to_nat(svector const& d, unsigned max_n); - static digit_t get_pos_mask(unsigned bit_idx) { - return (digit_t)1 << (digit_t)(bit_idx % (8 * sizeof(digit_t))); - } - static digit_t get_bit_word(svector const& bits, unsigned bit_idx) { - return bits[bit_idx / (8 * sizeof(digit_t))]; - } - - static digit_t& get_bit_word(svector& bits, unsigned bit_idx) { - return bits[bit_idx / (8 * sizeof(digit_t))]; - } std::ostream& display(std::ostream& out) const { out << "V:"; @@ -213,9 +211,9 @@ namespace bv { out << v[i], nz = true; if (!nz) out << "0"; - }; + }; - print_bits(bits); + print_bits(m_bits); out << " fix:"; print_bits(fixed); @@ -229,6 +227,25 @@ namespace bv { out << std::dec; return out; } + + private: + static digit_t get_pos_mask(unsigned bit_idx) { + return (digit_t)1 << (digit_t)(bit_idx % (8 * sizeof(digit_t))); + } + + static digit_t get_bit_word(svector const& bits, unsigned bit_idx) { + return bits[bit_idx / (8 * sizeof(digit_t))]; + } + + static digit_t& get_bit_word(svector& bits, unsigned bit_idx) { + return bits[bit_idx / (8 * sizeof(digit_t))]; + } + }; + + class sls_pre_valuation : public sls_valuation { + public: + sls_pre_valuation(unsigned bw):sls_valuation(bw) {} + svector& bits() { return m_bits; } }; inline std::ostream& operator<<(std::ostream& out, sls_valuation const& v) { return v.display(out); } From 48026edd7fe21cdc3bb707b9246cde1e121f77bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2024 10:35:51 -0800 Subject: [PATCH 28/69] move to hide bits Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls_eval.cpp | 3 ++- src/ast/sls/sls_valuation.h | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 4c5ed57fc..ceea3e7ba 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -39,7 +39,8 @@ namespace bv { if (bv.is_bv(e)) { auto& v = wval0(e); for (unsigned i = 0; i < v.bw; ++i) - v.set_bit(i, eval(e, i)); + v.set(m_tmp, i, eval(e, i)); + v.set(m_tmp); } else if (m.is_bool(e)) m_eval.setx(e->get_id(), eval(e, 0), false); diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index d67c0d6d2..3a14074e7 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -41,7 +41,7 @@ namespace bv { digit_t bits(unsigned i) const { return m_bits[i]; } svector const& bits() const { return m_bits; } - void set_bit(unsigned i, bool v) { set(m_bits, i, v); } + bool get_bit(unsigned i) const { return get(m_bits, i); } void set_value(svector& bits, rational const& r); @@ -228,6 +228,9 @@ namespace bv { return out; } + // TODO move: + void set_bit(unsigned i, bool v) { set(m_bits, i, v); } + private: static digit_t get_pos_mask(unsigned bit_idx) { return (digit_t)1 << (digit_t)(bit_idx % (8 * sizeof(digit_t))); @@ -246,6 +249,7 @@ namespace bv { public: sls_pre_valuation(unsigned bw):sls_valuation(bw) {} svector& bits() { return m_bits; } + }; inline std::ostream& operator<<(std::ostream& out, sls_valuation const& v) { return v.display(out); } From 74e73f2b8468ce2e43e9684b7f883f07d3e5a769 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2024 17:45:03 -0800 Subject: [PATCH 29/69] reorg to use datatypes --- src/ast/sls/bv_sls.cpp | 3 +- src/ast/sls/bv_sls_eval.cpp | 169 +++++++++----------- src/ast/sls/bv_sls_eval.h | 18 +-- src/ast/sls/bv_sls_fixed.cpp | 25 +-- src/ast/sls/sls_valuation.cpp | 261 ++++++++++++++++++------------- src/ast/sls/sls_valuation.h | 279 ++++++++++++++++++++-------------- 6 files changed, 414 insertions(+), 341 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 35f014773..e8402c957 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -211,8 +211,7 @@ namespace bv { mdl->register_decl(f, m.mk_bool_val(m_eval.bval0(e))); else if (bv.is_bv(e)) { auto const& v = m_eval.wval0(e); - rational n; - v.get_value(v.bits(), n); + rational n = v.get_value(); mdl->register_decl(f, bv.mk_numeral(n, v.bw)); } } diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index ceea3e7ba..5ccdc7540 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -470,7 +470,7 @@ namespace bv { case OP_BSHL: { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - auto sh = b.to_nat(b.bits(), b.bw); + auto sh = b.to_nat(b.bw); if (sh == 0) val.set(a.bits()); else if (sh >= b.bw) @@ -484,7 +484,7 @@ namespace bv { case OP_BLSHR: { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - auto sh = b.to_nat(b.bits(), b.bw); + auto sh = b.to_nat(b.bw); if (sh == 0) val.set(a.bits()); else if (sh >= b.bw) @@ -498,7 +498,7 @@ namespace bv { case OP_BASHR: { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); - auto sh = b.to_nat(b.bits(), b.bw); + auto sh = b.to_nat(b.bw); auto sign = a.sign(); if (sh == 0) val.set(a.bits()); @@ -636,8 +636,7 @@ namespace bv { } case OP_EXT_ROTATE_LEFT: { auto& b = wval0(e->get_arg(1)); - rational n; - b.get_value(b.bits(), n); + rational n = b.get_value(); n = mod(n, rational(val.bw)); SASSERT(n.is_unsigned()); mk_rotate_left(n.get_unsigned()); @@ -645,8 +644,7 @@ namespace bv { } case OP_EXT_ROTATE_RIGHT: { auto& b = wval0(e->get_arg(1)); - rational n; - b.get_value(b.bits(), n); + rational n = b.get_value(); n = mod(n, rational(val.bw)); SASSERT(n.is_unsigned()); mk_rotate_left(val.bw - n.get_unsigned()); @@ -694,10 +692,10 @@ namespace bv { return r; } - bool sls_eval::try_repair(app* e, unsigned i) { + bool sls_eval::try_repair(app* e, unsigned i) { if (is_fixed0(e->get_arg(i))) return false; - if (e->get_family_id() == basic_family_id) + else if (e->get_family_id() == basic_family_id) return try_repair_basic(e, i); if (e->get_family_id() == bv.get_family_id()) return try_repair_bv(e, i); @@ -1049,8 +1047,10 @@ namespace bv { if (parity_b > 0) b.shift_right(y, parity_b); y[a.nw] = 0; + a.nw = a.nw + 1; a.bw = 8 * sizeof(digit_t) * a.nw; + y.set_bw(a.bw); // x = 2 ^ b.bw a.set_zero(x); a.set(x, bw, true); @@ -1061,11 +1061,11 @@ namespace bv { a.set_one(nextb); rem.reserve(2 * a.nw); - SASSERT(a.le(y, x)); - while (a.gt(y, m_zero)) { - SASSERT(a.le(y, x)); + SASSERT(y <= x); + while (y > m_zero) { + SASSERT(y <= x); set_div(x, y, a.bw, quot, rem); // quot, rem := quot_rem(x, y) - SASSERT(a.le(rem, y)); + SASSERT(y >= rem); a.set(x, y); // x := y a.set(y, rem); // y := rem a.set(aux, nexta); // aux := nexta @@ -1080,6 +1080,7 @@ namespace bv { a.bw = bw; a.nw = a.nw - 1; + y.set_bw(0); // x*a + y*b = 1 #if Z3DEBUG @@ -1098,7 +1099,7 @@ namespace bv { verbose_stream() << m_tmp[i]; verbose_stream() << "\n"; #endif - SASSERT(b.is_one(m_tmp)); + SASSERT(m_tmp.is_one()); #endif e.get(m_tmp2); if (parity_e > 0 && parity_b > 0) @@ -1117,23 +1118,20 @@ namespace bv { auto inv_b = nb.pseudo_inverse(b.bw); rational na = mod(inv_b * ne, rational::power_of_two(a.bw)); a.set_value(m_tmp, na); - a.set_repair(random_bool(), m_tmp); -#endif - return true; + return a.set_repair(random_bool(), m_tmp); +#endif } bool sls_eval::try_repair_bnot(bvval const& e, bvval& a) { for (unsigned i = 0; i < e.nw; ++i) m_tmp[i] = ~e.bits()[i]; a.clear_overflow_bits(m_tmp); - a.set_repair(random_bool(), m_tmp); - return true; + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { - a.set_sub(m_tmp, m_zero, e.bits()); - a.set_repair(random_bool(), m_tmp); - return true; + e.set_sub(m_tmp, m_zero, e.bits()); + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { @@ -1147,38 +1145,35 @@ namespace bv { // a <=s b <-> a + p2 <=u b + p2 bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { - //add_p2_1(b, m_tmp4); a.set(m_tmp, b.bits()); if (e) { - a.set_repair(true, m_tmp); + return a.set_repair(true, m_tmp); } else { a.set_add(m_tmp2, m_tmp, m_one); - a.set_repair(false, m_tmp2); + return a.set_repair(false, m_tmp2); } - return true; } bool sls_eval::try_repair_sge(bool e, bvval& a, bvval const& b) { a.set(m_tmp, b.bits()); if (e) { - a.set_repair(false, m_tmp); + return a.set_repair(false, m_tmp); } else { a.set_sub(m_tmp2, m_tmp, m_one); - a.set_repair(true, m_tmp2); - } - return true; + return a.set_repair(true, m_tmp2); + } } - void sls_eval::add_p2_1(bvval const& a, svector& t) const { + void sls_eval::add_p2_1(bvval const& a, bvect& t) const { a.set(m_zero, a.bw - 1, true); a.set_add(t, a.bits(), m_zero); a.set(m_zero, a.bw - 1, false); a.clear_overflow_bits(t); } - bool sls_eval::try_repair_ule(bool e, bvval& a, svector const& t) { + bool sls_eval::try_repair_ule(bool e, bvval& a, bvect const& t) { if (e) { if (!a.get_at_most(t, m_tmp)) return false; @@ -1192,11 +1187,10 @@ namespace bv { return false; } } - a.set_repair(random_bool(), m_tmp); - return true; + return a.set_repair(random_bool(), m_tmp); } - bool sls_eval::try_repair_uge(bool e, bvval& a, svector const& t) { + bool sls_eval::try_repair_uge(bool e, bvval& a, bvect const& t) { if (e) { if (!a.get_at_least(t, m_tmp)) return false; @@ -1208,19 +1202,16 @@ namespace bv { if (!a.get_at_most(m_tmp2, m_tmp)) return false; } - a.set_repair(random_bool(), m_tmp); - return true; + return a.set_repair(random_bool(), m_tmp); } - bool sls_eval::try_repair_bit2bool(bvval& a, unsigned idx) { - a.set(m_tmp, a.bits()); - a.set(m_tmp, idx, !a.get_bit(idx)); - return a.try_set(m_tmp); + bool sls_eval::try_repair_bit2bool(bvval& a, unsigned idx) { + return a.try_set_bit(idx, !a.get_bit(idx)); } bool sls_eval::try_repair_shl(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { - unsigned sh = b.to_nat(b.bits(), b.bw); + unsigned sh = b.to_nat(b.bw); if (sh == 0) return a.try_set(e.bits()); else if (sh >= b.bw) @@ -1251,23 +1242,14 @@ namespace bv { bool sls_eval::try_repair_ashr(bvval const& e, bvval & a, bvval& b, unsigned i) { if (i == 0) { - unsigned sh = b.to_nat(b.bits(), b.bw); + unsigned sh = b.to_nat(b.bw); if (sh == 0) return a.try_set(e.bits()); else if (sh >= b.bw) { - if (e.get_bit(e.bw - 1)) { - if (!a.get_bit(a.bw - 1) && !a.get(a.fixed, a.bw - 1)) - a.set_bit(a.bw - 1, true); - else - return false; - } - else { - if (a.get_bit(a.bw - 1) && !a.get(a.fixed, a.bw - 1)) - a.set_bit(a.bw - 1, false); - else - return false; - } - return true; + if (e.get_bit(e.bw - 1)) + return a.try_set_bit(a.bw - 1, true); + else + return a.try_set_bit(a.bw - 1, false); } else { // e = a >> sh @@ -1289,7 +1271,6 @@ namespace bv { b.set(m_tmp, sh); return b.try_set(m_tmp); } - return false; } bool sls_eval::try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i) { @@ -1303,7 +1284,7 @@ namespace bv { bool sls_eval::try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { - if (e.is_zero() && a.is_ones(a.fixed) && a.is_ones()) + if (e.is_zero() && a.fixed.is_ones() && a.is_ones()) return false; if (b.is_zero()) return false; @@ -1311,14 +1292,13 @@ namespace bv { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = ~a.fixed[i] | a.bits()[i]; a.clear_overflow_bits(m_tmp); - if (a.lt(m_tmp, e.bits())) + if (e.bits() > m_tmp) return false; } // e = 1 => a := b if (e.is_one()) { a.set(m_tmp, b.bits()); - a.set_repair(false, m_tmp); - return true; + return a.set_repair(false, m_tmp); } // b * e + r = a for (unsigned i = 0; i < a.nw; ++i) @@ -1331,25 +1311,23 @@ namespace bv { for (unsigned i = 0; i < a.nw; ++i) m_tmp2[i] = random_bits(); b.clear_overflow_bits(m_tmp2); - while (b.gt(m_tmp2, b.bits())) + while (b.bits() < m_tmp2) b.set(m_tmp2, b.msb(m_tmp2), false); while (a.set_add(m_tmp3, m_tmp, m_tmp2)) b.set(m_tmp2, b.msb(m_tmp2), false); - a.set_repair(true, m_tmp3); + return a.set_repair(true, m_tmp3); } else { if (e.is_one() && a.is_zero()) { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = random_bits(); a.clear_overflow_bits(m_tmp); - b.set_repair(true, m_tmp); - return true; + return b.set_repair(true, m_tmp); } if (e.is_one()) { - b.set(m_tmp, a.bits()); - b.set_repair(true, m_tmp); - return true; - } + a.set(m_tmp, a.bits()); + return b.set_repair(true, m_tmp); + } // e * b + r = a // b = (a - r) udiv e @@ -1358,13 +1336,12 @@ namespace bv { m_tmp[i] = random_bits(); a.clear_overflow_bits(m_tmp); // ensure r <= m - while (a.lt(a.bits(), m_tmp)) + while (a.bits() < m_tmp) a.set(m_tmp, a.msb(m_tmp), false); a.set_sub(m_tmp2, a.bits(), m_tmp); set_div(m_tmp2, e.bits(), a.bw, m_tmp3, m_tmp4); - b.set_repair(random_bool(), m_tmp4); + return b.set_repair(random_bool(), m_tmp4); } - return true; } // table III in Niemetz et al @@ -1405,8 +1382,7 @@ namespace bv { b.set(m_tmp, i, false); } a.set_add(m_tmp3, m_tmp2, e.bits()); - a.set_repair(random_bool(), m_tmp3); - return true; + return a.set_repair(random_bool(), m_tmp3); } else { // a urem b = e: b*y + e = a @@ -1421,19 +1397,18 @@ namespace bv { a.set_sub(m_tmp2, a.bits(), e.bits()); set_div(m_tmp2, m_tmp, a.bw, m_tmp3, m_tmp4); a.clear_overflow_bits(m_tmp3); - b.set_repair(random_bool(), m_tmp3); - return true; + return b.set_repair(random_bool(), m_tmp3); } } - bool sls_eval::add_overflow_on_fixed(bvval const& a, svector const& t) { + bool sls_eval::add_overflow_on_fixed(bvval const& a, bvect const& t) { a.set(m_tmp3, m_zero); for (unsigned i = 0; i < a.nw; ++i) m_tmp3[i] = a.fixed[i] & a.bits()[i]; return a.set_add(m_tmp4, t, m_tmp3); } - bool sls_eval::mul_overflow_on_fixed(bvval const& a, svector const& t) { + bool sls_eval::mul_overflow_on_fixed(bvval const& a, bvect const& t) { a.set(m_tmp3, m_zero); for (unsigned i = 0; i < a.nw; ++i) m_tmp3[i] = a.fixed[i] & a.bits()[i]; @@ -1453,8 +1428,7 @@ namespace bv { bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { - rational n; - b.get_value(b.bits(), n); + rational n = b.get_value(); n = mod(n, rational(b.bw)); return try_repair_rotate_left(e, a, n.get_unsigned()); } @@ -1469,8 +1443,7 @@ namespace bv { bool sls_eval::try_repair_rotate_right(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { - rational n; - b.get_value(b.bits(), n); + rational n = b.get_value(); n = mod(b.bw - n, rational(b.bw)); return try_repair_rotate_left(e, a, n.get_unsigned()); } @@ -1478,8 +1451,7 @@ namespace bv { SASSERT(i == 1); unsigned sh = m_rand(b.bw); b.set(m_tmp, sh); - b.set_repair(random_bool(), m_tmp); - return true; + return b.set_repair(random_bool(), m_tmp); } } @@ -1488,32 +1460,32 @@ namespace bv { // maximize if (i == 0) { a.max_feasible(m_tmp); - a.set_repair(false, m_tmp); + return a.set_repair(false, m_tmp); } else { b.max_feasible(m_tmp); - b.set_repair(false, m_tmp); + return b.set_repair(false, m_tmp); } } else { // minimize if (i == 0) { a.min_feasible(m_tmp); - a.set_repair(true, m_tmp); + return a.set_repair(true, m_tmp); } else { b.min_feasible(m_tmp); - b.set_repair(true, m_tmp); + return b.set_repair(true, m_tmp); } } - return true; } bool sls_eval::try_repair_zero_ext(bvval const& e, bvval& a) { + bool change = false; for (unsigned i = 0; i < a.bw; ++i) - if (!a.get(a.fixed, i)) - a.set_bit(i, e.get_bit(i)); - return true; + if (a.try_set_bit(i, e.get_bit(i))) + change = true; + return change; } bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i) { @@ -1532,16 +1504,15 @@ namespace bv { } bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { + bool change = false; for (unsigned i = 0; i < e.bw; ++i) - if (a.get(a.fixed, i + lo) && a.get_bit(i + lo) != e.get_bit(i)) - return false; - for (unsigned i = 0; i < e.bw; ++i) - a.set_bit(i + lo, e.get_bit(i)); - return true; + if (a.try_set_bit(i + lo, e.get_bit(i))) + change = true; + return change; } - void sls_eval::set_div(svector const& a, svector const& b, unsigned bw, - svector& quot, svector& rem) const { + void sls_eval::set_div(bvect const& a, bvect const& b, unsigned bw, + bvect& quot, bvect& rem) const { unsigned nw = (bw + 8 * sizeof(digit_t) - 1) / (8 * sizeof(digit_t)); unsigned bnw = nw; while (bnw > 1 && b[bnw - 1] == 0) diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 4669c24b2..b379f7e85 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -40,8 +40,8 @@ namespace bv { bool_vector m_eval; // expr-id -> boolean valuation bool_vector m_fixed; // expr-id -> is Boolean fixed - mutable svector m_tmp, m_tmp2, m_tmp3, m_tmp4, m_zero, m_one, m_minus_one; - svector m_a, m_b, m_nextb, m_nexta, m_aux; + mutable bvect m_tmp, m_tmp2, m_tmp3, m_tmp4, m_zero, m_one, m_minus_one; + bvect m_a, m_b, m_nextb, m_nexta, m_aux; using bvval = sls_valuation; @@ -91,18 +91,18 @@ namespace bv { bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const; bool try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_rotate_right(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_ule(bool e, bvval& a, svector const& t); - bool try_repair_uge(bool e, bvval& a, svector const& t); + bool try_repair_ule(bool e, bvval& a, bvect const& t); + bool try_repair_uge(bool e, bvval& a, bvect const& t); bool try_repair_umul_ovfl(bool e, bvval& a, bvval& b, unsigned i); bool try_repair_zero_ext(bvval const& e, bvval& a); bool try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_extract(bvval const& e, bvval& a, unsigned lo); - void add_p2_1(bvval const& a, svector& t) const; + void add_p2_1(bvval const& a, bvect& t) const; - bool add_overflow_on_fixed(bvval const& a, svector const& t); - bool mul_overflow_on_fixed(bvval const& a, svector const& t); - void set_div(svector const& a, svector const& b, unsigned nw, - svector& quot, svector& rem) const; + bool add_overflow_on_fixed(bvval const& a, bvect const& t); + bool mul_overflow_on_fixed(bvval const& a, bvect const& t); + void set_div(bvect const& a, bvect const& b, unsigned nw, + bvect& quot, bvect& rem) const; digit_t random_bits(); bool random_bool() { return m_rand() % 2 == 0; } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 05d9599c1..0037bb5ca 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -110,7 +110,7 @@ namespace bv { } else if (bv.is_bit2bool(e, s, idx)) { auto& val = wval0(s); - val.set_bit(idx, !sign); + val.try_set_bit(idx, !sign); val.set(val.fixed, idx, true); val.init_fixed(); } @@ -259,6 +259,17 @@ namespace bv { case OP_BADD: { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); + rational r; + if (bv.is_numeral(e->get_arg(0), r) && b.has_range()) { + auto rlo = b.get_lo(); + auto rhi = b.get_hi(); + v.add_range(r + rlo, r + rhi); + } + if (bv.is_numeral(e->get_arg(1), r) && a.has_range()) { + auto rlo = a.get_lo(); + auto rhi = a.get_hi(); + v.add_range(r + rlo, r + rhi); + } bool pfixed = true; for (unsigned i = 0; i < v.bw; ++i) { if (pfixed && a.get(a.fixed, i) && b.get(b.fixed, i)) @@ -273,17 +284,7 @@ namespace bv { v.set(v.fixed, i, false); } } - rational r, rlo, rhi; - if (bv.is_numeral(e->get_arg(0), r) && !b.eq(b.lo, b.hi)) { - b.get_value(b.lo, rlo); - b.get_value(b.hi, rhi); - v.add_range(r + rlo, r + rhi); - } - if (bv.is_numeral(e->get_arg(1), r) && !a.eq(a.lo, a.hi)) { - a.get_value(a.lo, rlo); - a.get_value(a.hi, rhi); - v.add_range(r + rlo, r + rhi); - } + break; } case OP_BMUL: { diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 03daab05b..a0a21a534 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -22,12 +22,73 @@ Author: namespace bv { - sls_valuation::sls_valuation(unsigned bw): bw(bw) { + void bvect::set_bw(unsigned bw) { + this->bw = bw; nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); - lo.reserve(nw + 1); - hi.reserve(nw + 1); - m_bits.reserve(nw + 1); - fixed.reserve(nw + 1); + mask = (1 << (bw % (8 * sizeof(digit_t)))) - 1; + if (mask == 0) + mask = ~(digit_t)0; + reserve(nw + 1); + } + + void bvect::clear_overflow_bits() { + SASSERT(nw > 0); + (*this)[nw - 1] &= mask; + SASSERT(!has_overflow()); + } + + void bvect::set_sub(bvect const& a, bvect const& b) { + digit_t c; + mpn_manager().sub(a.data(), a.nw, b.data(), a.nw, data(), &c); + set_bw(bw); + clear_overflow_bits(); + } + + bool operator==(bvect const& a, bvect const& b) { + SASSERT(a.nw > 0); + SASSERT(!a.has_overflow()); + SASSERT(!b.has_overflow()); + return 0 == mpn_manager().compare(a.data(), a.nw, b.data(), a.nw); + } + + bool operator<(bvect const& a, bvect const& b) { + SASSERT(a.nw > 0); + SASSERT(!a.has_overflow()); + SASSERT(!b.has_overflow()); + return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) < 0; + } + + bool operator>(bvect const& a, bvect const& b) { + SASSERT(a.nw > 0); + SASSERT(!a.has_overflow()); + SASSERT(!b.has_overflow()); + return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) > 0; + } + + bool operator<=(bvect const& a, bvect const& b) { + SASSERT(a.nw > 0); + SASSERT(!a.has_overflow()); + SASSERT(!b.has_overflow()); + return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) <= 0; + } + + bool operator>=(bvect const& a, bvect const& b) { + SASSERT(a.nw > 0); + SASSERT(!a.has_overflow()); + SASSERT(!b.has_overflow()); + return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) >= 0; + } + + + sls_valuation::sls_valuation(unsigned bw) : bw(bw) { + nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); + mask = (1 << (bw % (8 * sizeof(digit_t)))) - 1; + if (mask == 0) + mask = ~(digit_t)0; + lo.set_bw(bw); + hi.set_bw(bw); + m_bits.set_bw(bw); + fixed.set_bw(bw); // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated for (unsigned i = 0; i < nw; ++i) lo[i] = 0, hi[i] = 0, m_bits[i] = 0, fixed[i] = 0; @@ -35,8 +96,8 @@ namespace bv { set(fixed, i, true); } - bool sls_valuation::in_range(svector const& bits) const { - mpn_manager m; + bool sls_valuation::in_range(bvect const& bits) const { + mpn_manager m; auto c = m.compare(lo.data(), nw, hi.data(), nw); SASSERT(!has_overflow(bits)); // full range @@ -53,39 +114,6 @@ namespace bv { m.compare(bits.data(), nw, hi.data(), nw) < 0; } - bool sls_valuation::eq(svector const& a, svector const& b) const { - SASSERT(!has_overflow(a)); - SASSERT(!has_overflow(b)); - return 0 == memcmp(a.data(), b.data(), num_bytes()); - } - - bool sls_valuation::gt(svector const& a, svector const& b) const { - SASSERT(!has_overflow(a)); - SASSERT(!has_overflow(b)); - mpn_manager m; - return m.compare(a.data(), nw, b.data(), nw) > 0; - } - - bool sls_valuation::lt(svector const& a, svector const& b) const { - SASSERT(!has_overflow(a)); - SASSERT(!has_overflow(b)); - mpn_manager m; - return m.compare(a.data(), nw, b.data(), nw) < 0; - } - - bool sls_valuation::le(svector const& a, svector const& b) const { - SASSERT(!has_overflow(a)); - SASSERT(!has_overflow(b)); - mpn_manager m; - return m.compare(a.data(), nw, b.data(), nw) <= 0; - } - - void sls_valuation::clear_overflow_bits(svector& bits) const { - for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) - set(bits, i, false); - SASSERT(!has_overflow(bits)); - } - // // largest dst <= src and dst is feasible // set dst := src & (~fixed | bits) @@ -100,7 +128,7 @@ namespace bv { // set dst := hi - 1 // - bool sls_valuation::get_at_most(svector const& src, svector& dst) const { + bool sls_valuation::get_at_most(bvect const& src, bvect& dst) const { SASSERT(!has_overflow(src)); for (unsigned i = 0; i < nw; ++i) dst[i] = src[i] & (~fixed[i] | m_bits[i]); @@ -137,7 +165,7 @@ namespace bv { // if hi <= dst < lo // set dst := lo // - bool sls_valuation::get_at_least(svector const& src, svector& dst) const { + bool sls_valuation::get_at_least(bvect const& src, bvect& dst) const { SASSERT(!has_overflow(src)); for (unsigned i = 0; i < nw; ++i) dst[i] = (~fixed[i] & src[i]) | (fixed[i] & m_bits[i]); @@ -161,51 +189,52 @@ namespace bv { return round_up(dst); } - bool sls_valuation::round_up(svector& dst) const { - if (lt(lo, hi)) { - if (le(hi, dst)) + bool sls_valuation::round_up(bvect& dst) const { + if (lo < hi) { + if (hi <= dst) return false; - if (lt(dst, lo)) + if (lo > dst) set(dst, lo); } - else if (le(hi, dst) && lt(dst, lo)) + else if (hi <= dst && lo > dst) set(dst, lo); SASSERT(!has_overflow(dst)); return true; } - bool sls_valuation::round_down(svector& dst) const { - if (lt(lo, hi)) { - if (lt(dst, lo)) + bool sls_valuation::round_down(bvect& dst) const { + if (lo < hi) { + if (lo > dst) return false; - if (le(hi, dst)) { + if (hi <= dst) { set(dst, hi); sub1(dst); } } - else if (le(hi, dst) && lt(dst, lo)) { + else if (hi <= dst && lo > dst) { set(dst, hi); sub1(dst); } - SASSERT(!has_overflow(dst)); + SASSERT(well_formed()); return true; } - bool sls_valuation::set_repair(bool try_down, svector& dst) { + bool sls_valuation::set_repair(bool try_down, bvect& dst) { for (unsigned i = 0; i < nw; ++i) dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); bool ok = try_down ? round_down(dst) : round_up(dst); if (!ok) VERIFY(try_down ? round_up(dst) : round_down(dst)); - if (eq(m_bits, dst)) + DEBUG_CODE(SASSERT(0 == (mask & (fixed[nw-1] & (m_bits[nw-1] ^ dst[nw-1])))); for (unsigned i = 0; i + 1 < nw; ++i) SASSERT(0 == (fixed[i] & (m_bits[i] ^ dst[i])));); + if (m_bits == dst) return false; set(m_bits, dst); - SASSERT(!has_overflow(dst)); + SASSERT(well_formed()); return true; } - void sls_valuation::min_feasible(svector& out) const { - if (gt(hi, lo)) { + void sls_valuation::min_feasible(bvect& out) const { + if (lo < hi) { for (unsigned i = 0; i < nw; ++i) out[i] = lo[i]; } @@ -216,8 +245,8 @@ namespace bv { SASSERT(!has_overflow(out)); } - void sls_valuation::max_feasible(svector& out) const { - if (gt(hi, lo)) { + void sls_valuation::max_feasible(bvect& out) const { + if (lo < hi) { for (unsigned i = 0; i < nw; ++i) out[i] = hi[i]; sub1(out); @@ -229,53 +258,49 @@ namespace bv { SASSERT(!has_overflow(out)); } - unsigned sls_valuation::msb(svector const& src) const { + unsigned sls_valuation::msb(bvect const& src) const { SASSERT(!has_overflow(src)); - for (unsigned i = nw; i-- > 0; ) + for (unsigned i = nw; i-- > 0; ) if (src[i] != 0) - return i * 8 * sizeof(digit_t) + log2(src[i]); + return i * 8 * sizeof(digit_t) + log2(src[i]); return bw; } - void sls_valuation::set_value(svector& bits, rational const& n) { - for (unsigned i = 0; i < bw; ++i) - set(bits, i, n.get_bit(i)); + void sls_valuation::set_value(bvect& bits, rational const& n) { + for (unsigned i = 0; i < bw; ++i) + bits.set(i, n.get_bit(i)); clear_overflow_bits(bits); } - void sls_valuation::get_value(svector const& bits, rational& r) const { - rational p(1); - r = 0; + rational sls_valuation::get_value(bvect const& bits) const { + rational p(1), r(0); for (unsigned i = 0; i < nw; ++i) { r += p * rational(bits[i]); - p *= rational::power_of_two(8*sizeof(digit_t)); + p *= rational::power_of_two(8 * sizeof(digit_t)); } + return r; } - void sls_valuation::get(svector& dst) const { + void sls_valuation::get(bvect& dst) const { for (unsigned i = 0; i < nw; ++i) dst[i] = m_bits[i]; } - void sls_valuation::set1(svector& bits) { - for (unsigned i = 0; i < bw; ++i) - set(bits, i, true); - } - // // new_bits != bits => ~fixed // 0 = (new_bits ^ bits) & fixed // also check that new_bits are in range // - bool sls_valuation::can_set(svector const& new_bits) const { + bool sls_valuation::can_set(bvect const& new_bits) const { SASSERT(!has_overflow(new_bits)); for (unsigned i = 0; i < nw; ++i) if (0 != ((new_bits[i] ^ m_bits[i]) & fixed[i])) - return false; + return false; return in_range(new_bits); } - unsigned sls_valuation::to_nat(svector const& d, unsigned max_n) { + unsigned sls_valuation::to_nat(unsigned max_n) { + bvect const& d = m_bits; SASSERT(!has_overflow(d)); SASSERT(max_n < UINT_MAX / 2); unsigned p = 1; @@ -287,34 +312,36 @@ namespace bv { return max_n; return value; } - if (get(d, i)) - value += p; + if (get(d, i)) + value += p; p <<= 1; } return value; } - void sls_valuation::shift_right(svector& out, unsigned shift) const { + void sls_valuation::shift_right(bvect& out, unsigned shift) const { SASSERT(shift < bw); for (unsigned i = 0; i < bw; ++i) set(out, i, i + shift < bw ? get(m_bits, i + shift) : false); - SASSERT(!has_overflow(out)); + SASSERT(well_formed()); } void sls_valuation::add_range(rational l, rational h) { + l = mod(l, rational::power_of_two(bw)); h = mod(h, rational::power_of_two(bw)); if (h == l) return; - - if (eq(lo, hi)) { + + SASSERT(is_zero(fixed)); // ranges can only be added before fixed bits are set. + + if (lo == hi) { set_value(lo, l); set_value(hi, h); } - else { - rational old_lo, old_hi; - get_value(lo, old_lo); - get_value(hi, old_hi); + else { + auto old_lo = get_value(lo); + auto old_hi = get_value(hi); if (old_lo < old_hi) { if (old_lo < l && l < old_hi) set_value(lo, l), @@ -332,10 +359,12 @@ namespace bv { else if (old_hi < old_lo && (h < old_hi || old_lo < h)) set_value(hi, h); } - } + } SASSERT(!has_overflow(lo)); SASSERT(!has_overflow(hi)); - init_fixed(); + if (!in_range(m_bits)) + set(m_bits, lo); + SASSERT(well_formed()); } // @@ -352,7 +381,7 @@ namespace bv { // lo < hi, set most significant bits based on hi // void sls_valuation::init_fixed() { - if (eq(lo, hi)) + if (lo == hi) return; for (unsigned i = bw; i-- > 0; ) { if (!get(fixed, i)) @@ -370,8 +399,8 @@ namespace bv { } break; } - svector hi1(nw + 1, (unsigned)0); - svector one(nw + 1, (unsigned)0); + bvect hi1(nw + 1); + bvect one(nw + 1); one[0] = 1; digit_t c; mpn_manager().sub(hi.data(), nw, one.data(), nw, hi1.data(), &c); @@ -401,14 +430,14 @@ namespace bv { set(fixed, i, true); set(m_bits, i, b); } - }; + }; // set most significant bits - if (lt(lo, hi)) { + if (lo < hi) { unsigned i = bw; - for (; i-- > 0 && !get(hi, i); ) + for (; i-- > 0 && !get(hi, i); ) set_fixed_bit(i, false); - + if (is_power_of2(hi)) set_fixed_bit(i, false); } @@ -416,30 +445,31 @@ namespace bv { // lo + 1 = hi: then bits = lo mpn_manager().add(lo.data(), nw, one.data(), nw, hi1.data(), nw + 1, &c); clear_overflow_bits(hi1); - if (eq(hi1, hi)) { + if (hi == hi1) { for (unsigned i = 0; i < bw; ++i) - set_fixed_bit(i, get(lo, i)); + set_fixed_bit(i, get(lo, i)); } - SASSERT(!has_overflow(m_bits)); + SASSERT(well_formed()); } - void sls_valuation::set_sub(svector& out, svector const& a, svector const& b) const { + void sls_valuation::set_sub(bvect& out, bvect const& a, bvect const& b) const { digit_t c; mpn_manager().sub(a.data(), nw, b.data(), nw, out.data(), &c); clear_overflow_bits(out); + out.set_bw(bw); } - bool sls_valuation::set_add(svector& out, svector const& a, svector const& b) const { + bool sls_valuation::set_add(bvect& out, bvect const& a, bvect const& b) const { digit_t c; mpn_manager().add(a.data(), nw, b.data(), nw, out.data(), nw + 1, &c); bool ovfl = out[nw] != 0 || has_overflow(out); clear_overflow_bits(out); + out.set_bw(bw); return ovfl; } - bool sls_valuation::set_mul(svector& out, svector const& a, svector const& b, bool check_overflow) const { + bool sls_valuation::set_mul(bvect& out, bvect const& a, bvect const& b, bool check_overflow) const { mpn_manager().mul(a.data(), nw, b.data(), nw, out.data()); - bool ovfl = false; if (check_overflow) { ovfl = has_overflow(out); @@ -447,14 +477,33 @@ namespace bv { ovfl |= out[i] != 0; } clear_overflow_bits(out); + out.set_bw(bw); return ovfl; } - bool sls_valuation::is_power_of2(svector const& src) const { + bool sls_valuation::is_power_of2(bvect const& src) const { unsigned c = 0; for (unsigned i = 0; i < nw; ++i) c += get_num_1bits(src[i]); return c == 1; } + std::ostream& sls_valuation::print_bits(std::ostream& out, bvect const& v) const { + bool nz = false; + for (unsigned i = nw; i-- > 0;) { + auto w = v[i]; + if (i + 1 == nw) + w &= mask; + if (nz) + out << std::setw(8) << std::setfill('0') << w; + else if (w != 0) + out << w, nz = true; + } + + if (!nz) + out << "0"; + return out; + } + + } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 3a14074e7..88b8efa59 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -27,124 +27,195 @@ Author: namespace bv { + + + class bvect : public svector { + unsigned bw = 0; + unsigned nw = 0; + unsigned mask = 0; + public: + bvect() {} + bvect(unsigned sz): svector(sz, (unsigned)0) {} + void set_bw(unsigned bw); + + void clear_overflow_bits(); + void set_sub(bvect const& a, bvect const& b); + + bool is_one() const { + SASSERT(bw > 0); + SASSERT(!has_overflow()); + for (unsigned i = 1; i < nw; ++i) + if (0 != (*this)[i]) + return false; + return 1 == (*this)[0]; + } + + bool is_ones() const { + SASSERT(bw > 0); + auto const& a = *this; + for (unsigned i = 0; i + 1 < nw; ++i) + if (0 != ~a[i]) + return false; + return ((~a[nw - 1]) & mask) == 0; + } + + bool is_zero() const { + SASSERT(bw > 0); + auto const& a = *this; + for (unsigned i = 0; i + 1 < nw; ++i) + if (a[i] != 0) + return false; + return (a[nw - 1] & mask) == 0; + } + + bool has_overflow() const { + SASSERT(bw > 0); + for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) + if (get(i)) + return true; + return false; + } + + bool get(unsigned bit_idx) const { + return (get_bit_word(bit_idx) & get_pos_mask(bit_idx)) != 0; + } + + + unsigned parity() const { + SASSERT(bw > 0); + SASSERT(!has_overflow()); + for (unsigned i = 0; i < nw; ++i) + if ((*this)[i] != 0) + return (8 * sizeof(digit_t) * i) + trailing_zeros((*this)[i]); + return bw; + } + + friend bool operator==(bvect const& a, bvect const& b); + friend bool operator<(bvect const& a, bvect const& b); + friend bool operator>(bvect const& a, bvect const& b); + friend bool operator<=(bvect const& a, bvect const& b); + friend bool operator>=(bvect const& a, bvect const& b); + + private: + + static digit_t get_pos_mask(unsigned bit_idx) { + return (digit_t)1 << (digit_t)(bit_idx % (8 * sizeof(digit_t))); + } + + digit_t get_bit_word(unsigned bit_idx) const { + return (*this)[bit_idx / (8 * sizeof(digit_t))]; + } + + digit_t& get_bit_word(unsigned bit_idx) { + return (*this)[bit_idx / (8 * sizeof(digit_t))]; + } + }; + + bool operator==(bvect const& a, bvect const& b); + bool operator<(bvect const& a, bvect const& b); + bool operator<=(bvect const& a, bvect const& b); + bool operator>=(bvect const& a, bvect const& b); + bool operator>(bvect const& a, bvect const& b); + inline bool operator!=(bvect const& a, bvect const& b) { return !(a == b); } + class sls_valuation { protected: - svector m_bits; + bvect m_bits; + bvect lo, hi; // range assignment to bit-vector, as wrap-around interval + + unsigned mask; + rational get_value(bvect const& bits) const; + bool round_up(bvect& dst) const; + bool round_down(bvect& dst) const; + + std::ostream& print_bits(std::ostream& out, bvect const& bits) const; + + public: unsigned bw; // bit-width unsigned nw; // num words - svector lo, hi; // range assignment to bit-vector, as wrap-around interval - svector fixed; // bit assignment and don't care bit + bvect fixed; // bit assignment and don't care bit sls_valuation(unsigned bw); unsigned num_bytes() const { return (bw + 7) / 8; } digit_t bits(unsigned i) const { return m_bits[i]; } - svector const& bits() const { return m_bits; } + bvect const& bits() const { return m_bits; } bool get_bit(unsigned i) const { return get(m_bits, i); } + bool try_set_bit(unsigned i, bool b) { + if (get(fixed, i) && get_bit(i) != b) + return false; + set(m_bits, i, b); + return true; + } - void set_value(svector& bits, rational const& r); - void get_value(svector const& bits, rational& r) const; - void get(svector& dst) const; + void set_value(bvect& bits, rational const& r); + + rational get_value() const { return get_value(m_bits); } + rational get_lo() const { return get_value(lo); } + rational get_hi() const { return get_value(hi); } + + void get(bvect& dst) const; void add_range(rational lo, rational hi); + bool has_range() const { return lo != hi; } void init_fixed(); - void set1(svector& bits); - void clear_overflow_bits(svector& bits) const; - bool in_range(svector const& bits) const; - bool can_set(svector const& bits) const; + void clear_overflow_bits(bvect& bits) const { bits.clear_overflow_bits(); } + bool in_range(bvect const& bits) const; + bool can_set(bvect const& bits) const; bool eq(sls_valuation const& other) const { return eq(other.m_bits); } + bool eq(bvect const& other) const { return other == m_bits; } - bool eq(svector const& other) const { return eq(other, m_bits); } - bool eq(svector const& a, svector const& b) const; - bool gt(svector const& a, svector const& b) const; - bool lt(svector const& a, svector const& b) const; - bool le(svector const& a, svector const& b) const; + bool is_zero() const { return m_bits.is_zero(); } + bool is_zero(bvect const& a) const { return a.is_zero(); } - bool is_zero() const { return is_zero(m_bits); } - bool is_zero(svector const& a) const { - for (unsigned i = 0; i < nw; ++i) - if (a[i] != 0) - return false; - return true; - } - bool is_ones() const { return is_ones(m_bits); } - bool is_ones(svector const& a) const { - auto bound = bw % (sizeof(digit_t) * 8) == 0 ? nw : nw - 1; - for (unsigned i = 0; i < bound; ++i) - if (a[i] != (a[i] ^ 0)) - return false; - if (bound < nw) { - for (unsigned i = bound * sizeof(digit_t) * 8; i < bw; ++i) - if (!get(a, i)) - return false; - } - return true; - } + bool is_ones() const { return m_bits.is_ones(); } - bool is_one() const { return is_one(m_bits); } - bool is_one(svector const& bits) const { - if (1 != bits[0]) - return false; - for (unsigned i = 1; i < nw; ++i) - if (0 != bits[i]) - return false; - return true; - } + bool is_one() const { return m_bits.is_one(); } + // bool is_one(bvect const& a) const { return a.is_one(); } bool sign() const { return get(m_bits, bw - 1); } - bool has_overflow(svector const& bits) const { - for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) - if (get(bits, i)) - return true; - return false; - } + bool has_overflow(bvect const& bits) const { return bits.has_overflow(); } - unsigned parity(svector const& bits) const { - for (unsigned i = 0; i < nw; ++i) - if (bits[i] != 0) - return (8 * sizeof(digit_t) * i) + trailing_zeros(bits[i]); - return bw; - } + unsigned parity(bvect const& bits) const { return bits.parity(); } - void min_feasible(svector& out) const; - void max_feasible(svector& out) const; + void min_feasible(bvect& out) const; + void max_feasible(bvect& out) const; // most significant bit or bw if src = 0 - unsigned msb(svector const& src) const; + unsigned msb(bvect const& src) const; - bool is_power_of2(svector const& src) const; + bool is_power_of2(bvect const& src) const; // retrieve largest number at or below (above) src which is feasible // with respect to fixed, lo, hi. - bool get_at_most(svector const& src, svector& dst) const; - bool get_at_least(svector const& src, svector& dst) const; - bool round_up(svector& dst) const; - bool round_down(svector& dst) const; - bool set_repair(bool try_down, svector& dst); + bool get_at_most(bvect const& src, bvect& dst) const; + bool get_at_least(bvect const& src, bvect& dst) const; - bool try_set(svector const& src) { + bool set_repair(bool try_down, bvect& dst); + + bool try_set(bvect const& src) { if (!can_set(src)) return false; set(src); return true; } - void set(svector const& src) { + void set(bvect const& src) { for (unsigned i = nw; i-- > 0; ) m_bits[i] = src[i]; clear_overflow_bits(m_bits); } - void set_zero(svector& out) const { + void set_zero(bvect& out) const { for (unsigned i = 0; i < nw; ++i) out[i] = 0; } - void set_one(svector& out) const { + void set_one(bvect& out) const { for (unsigned i = 1; i < nw; ++i) out[i] = 0; out[0] = 1; @@ -154,7 +225,7 @@ namespace bv { set_zero(m_bits); } - void sub1(svector& out) const { + void sub1(bvect& out) const { for (unsigned i = 0; i < bw; ++i) { if (get(out, i)) { set(out, i, false); @@ -165,90 +236,72 @@ namespace bv { } } - void set_sub(svector& out, svector const& a, svector const& b) const; - bool set_add(svector& out, svector const& a, svector const& b) const; - bool set_mul(svector& out, svector const& a, svector const& b, bool check_overflow = true) const; - void shift_right(svector& out, unsigned shift) const; + void set_sub(bvect& out, bvect const& a, bvect const& b) const; + bool set_add(bvect& out, bvect const& a, bvect const& b) const; + bool set_mul(bvect& out, bvect const& a, bvect const& b, bool check_overflow = true) const; + void shift_right(bvect& out, unsigned shift) const; - void set_range(svector& dst, unsigned lo, unsigned hi, bool b) { + void set_range(bvect& dst, unsigned lo, unsigned hi, bool b) { for (unsigned i = lo; i < hi; ++i) set(dst, i, b); } - void set(svector& d, unsigned bit_idx, bool val) const { - auto _val = static_cast(0 - static_cast(val)); - get_bit_word(d, bit_idx) ^= (_val ^ get_bit_word(d, bit_idx)) & get_pos_mask(bit_idx); + void set(bvect& d, unsigned bit_idx, bool val) const { + d.set(bit_idx, val); } - void set(svector& dst, unsigned v) const { + void set(bvect& dst, unsigned v) const { dst[0] = v; for (unsigned i = 1; i < nw; ++i) dst[i] = 0; } - void set(svector& dst, svector const& src) const { + void set(bvect& dst, bvect const& src) const { for (unsigned i = 0; i < nw; ++i) dst[i] = src[i]; } - bool get(svector const& d, unsigned bit_idx) const { - return (get_bit_word(d, bit_idx) & get_pos_mask(bit_idx)) != 0; + bool get(bvect const& d, unsigned bit_idx) const { + return d.get(bit_idx); } - unsigned to_nat(svector const& d, unsigned max_n); - - + unsigned to_nat(unsigned max_n); std::ostream& display(std::ostream& out) const { out << "V:"; out << std::hex; - auto print_bits = [&](svector const& v) { - bool nz = false; - for (unsigned i = nw; i-- > 0;) - if (nz) - out << std::setw(8) << std::setfill('0') << v[i]; - else if (v[i] != 0) - out << v[i], nz = true; - if (!nz) - out << "0"; - }; - print_bits(m_bits); + print_bits(out, m_bits); out << " fix:"; - print_bits(fixed); + print_bits(out, fixed); - if (!eq(lo, hi)) { + if (lo != hi) { out << " ["; - print_bits(lo); + print_bits(out, lo); out << ", "; - print_bits(hi); + print_bits(out, hi); out << "["; } out << std::dec; return out; } - // TODO move: - void set_bit(unsigned i, bool v) { set(m_bits, i, v); } + bool well_formed() const { + return !has_overflow(m_bits) && (!has_range() || in_range(m_bits)); + } private: - static digit_t get_pos_mask(unsigned bit_idx) { - return (digit_t)1 << (digit_t)(bit_idx % (8 * sizeof(digit_t))); - } - static digit_t get_bit_word(svector const& bits, unsigned bit_idx) { - return bits[bit_idx / (8 * sizeof(digit_t))]; - } - static digit_t& get_bit_word(svector& bits, unsigned bit_idx) { - return bits[bit_idx / (8 * sizeof(digit_t))]; - } + }; class sls_pre_valuation : public sls_valuation { public: sls_pre_valuation(unsigned bw):sls_valuation(bw) {} - svector& bits() { return m_bits; } + bvect& bits() { return m_bits; } + void set_bit(unsigned i, bool v) { set(m_bits, i, v); } + }; From 63804c52962837d33e1fe633ec68e6b0a30d603d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2024 21:19:06 -0800 Subject: [PATCH 30/69] na --- src/ast/sls/bv_sls.cpp | 2 +- src/ast/sls/bv_sls_eval.cpp | 87 ++++++++++++----------- src/ast/sls/bv_sls_fixed.cpp | 44 ++++++------ src/ast/sls/sls_valuation.cpp | 84 +++++++++-------------- src/ast/sls/sls_valuation.h | 126 ++++++++++++++-------------------- 5 files changed, 148 insertions(+), 195 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index e8402c957..e091eb4b5 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -67,7 +67,7 @@ namespace bv { } else if (bv.is_bv(e)) { auto& w = m_eval.wval0(e); - if (w.get(w.fixed, i) || should_keep()) + if (w.fixed.get(i) || should_keep()) return w.get_bit(i); } return m_rand() % 2 == 0; diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 5ccdc7540..5a26dc55b 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -39,7 +39,7 @@ namespace bv { if (bv.is_bv(e)) { auto& v = wval0(e); for (unsigned i = 0; i < v.bw; ++i) - v.set(m_tmp, i, eval(e, i)); + m_tmp.set(i, eval(e, i)); v.set(m_tmp); } else if (m.is_bool(e)) @@ -462,10 +462,10 @@ namespace bv { break; } case OP_BIT0: - val.set(val.bits(), 0, false); + val.bits().set(0, false); break; case OP_BIT1: - val.set(val.bits(), 0, true); + val.bits().set(0, true); break; case OP_BSHL: { auto& a = wval0(e->get_arg(0)); @@ -477,7 +477,7 @@ namespace bv { val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits(), i, i >= sh && a.get_bit(i - sh)); + val.bits().set(i, i >= sh && a.get_bit(i - sh)); } break; } @@ -491,7 +491,7 @@ namespace bv { val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.set(val.bits(), i, i + sh < a.bw && a.get_bit(i + sh)); + val.bits().set(i, i + sh < a.bw && a.get_bit(i + sh)); } break; } @@ -511,7 +511,7 @@ namespace bv { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = 0; for (unsigned i = 0; i < a.bw; ++i) - val.set(m_tmp, i, i + sh < a.bw && a.get_bit(i + sh)); + m_tmp.set(i, i + sh < a.bw && a.get_bit(i + sh)); if (sign) val.set_range(m_tmp, a.bw - sh, a.bw, true); val.set(m_tmp); @@ -521,7 +521,7 @@ namespace bv { case OP_SIGN_EXT: { auto& a = wval0(e->get_arg(0)); for (unsigned i = 0; i < a.bw; ++i) - val.set(m_tmp, i, a.get_bit(i)); + m_tmp.set(i, a.get_bit(i)); bool sign = a.sign(); val.set_range(m_tmp, a.bw, val.bw, sign); val.set(m_tmp); @@ -530,7 +530,7 @@ namespace bv { case OP_ZERO_EXT: { auto& a = wval0(e->get_arg(0)); for (unsigned i = 0; i < a.bw; ++i) - val.set(m_tmp, i, a.get_bit(i)); + m_tmp.set(i, a.get_bit(i)); val.set_range(m_tmp, a.bw, val.bw, false); val.set(m_tmp); break; @@ -904,12 +904,12 @@ namespace bv { unsigned start = m_rand(a.bw); for (unsigned idx = 0; idx < a.bw; ++idx) { unsigned j = (idx + start) % a.bw; - if (!a.get(a.fixed, j)) { - a.set(m_tmp, idx, !b.get_bit(j)); + if (!a.fixed.get(j)) { + m_tmp.set(idx, !b.get_bit(j)); bool r = a.try_set(m_tmp); if (r) return true; - a.set(m_tmp, j, b.get_bit(j)); + m_tmp.set(j, b.get_bit(j)); } } // could be due to bounds? @@ -1042,18 +1042,18 @@ namespace bv { // x*ta + y*tb = x - auto bw = a.bw; + b.get(y); if (parity_b > 0) b.shift_right(y, parity_b); + y[a.nw] = 0; - - a.nw = a.nw + 1; - a.bw = 8 * sizeof(digit_t) * a.nw; - y.set_bw(a.bw); - // x = 2 ^ b.bw + x[a.nw] = 0; + + a.set_bw((a.nw + 1)* 8 * sizeof(digit_t)); + y.set_bw(a.bw); // enable comparisons a.set_zero(x); - a.set(x, bw, true); + x.set(b.bw, true); // x = 2 ^ b.bw a.set_one(ta); a.set_zero(tb); @@ -1078,8 +1078,7 @@ namespace bv { a.set(tb, aux); // tb := aux } - a.bw = bw; - a.nw = a.nw - 1; + a.set_bw(b.bw); y.set_bw(0); // x*a + y*b = 1 @@ -1099,7 +1098,7 @@ namespace bv { verbose_stream() << m_tmp[i]; verbose_stream() << "\n"; #endif - SASSERT(m_tmp.is_one()); + SASSERT(a.is_one(m_tmp)); #endif e.get(m_tmp2); if (parity_e > 0 && parity_b > 0) @@ -1130,6 +1129,7 @@ namespace bv { } bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { + e.set_sub(m_tmp, m_zero, e.bits()); return a.set_repair(random_bool(), m_tmp); } @@ -1167,9 +1167,9 @@ namespace bv { } void sls_eval::add_p2_1(bvval const& a, bvect& t) const { - a.set(m_zero, a.bw - 1, true); + m_zero.set(a.bw - 1, true); a.set_add(t, a.bits(), m_zero); - a.set(m_zero, a.bw - 1, false); + m_zero.set(a.bw - 1, false); a.clear_overflow_bits(t); } @@ -1183,9 +1183,8 @@ namespace bv { a.set_add(m_tmp2, t, m_one); if (a.is_zero(m_tmp2)) return false; - if (!a.get_at_least(m_tmp2, m_tmp)) { - return false; - } + if (!a.get_at_least(m_tmp2, m_tmp)) + return false; } return a.set_repair(random_bool(), m_tmp); } @@ -1224,9 +1223,9 @@ namespace bv { // a[bw - 1: bw - sh] = unchanged // for (unsigned i = 0; i < e.bw - sh; ++i) - e.set(m_tmp, i, e.get_bit(sh + i)); + m_tmp.set(i, e.get_bit(sh + i)); for (unsigned i = e.bw - sh; i < e.bw; ++i) - e.set(m_tmp, i, a.get_bit(i)); + m_tmp.set(i, a.get_bit(i)); return a.try_set(m_tmp); } } @@ -1257,9 +1256,9 @@ namespace bv { // a[sh-1:0] = a[sh-1:0] // ignore sign for (unsigned i = sh; i < a.bw; ++i) - a.set(m_tmp, i, e.get_bit(i - sh)); + m_tmp.set(i, e.get_bit(i - sh)); for (unsigned i = 0; i < sh; ++i) - a.set(m_tmp, i, a.get_bit(i)); + m_tmp.set(i, a.get_bit(i)); a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } @@ -1284,7 +1283,7 @@ namespace bv { bool sls_eval::try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { - if (e.is_zero() && a.fixed.is_ones() && a.is_ones()) + if (e.is_zero() && a.is_ones(a.fixed) && a.is_ones()) return false; if (b.is_zero()) return false; @@ -1306,15 +1305,15 @@ namespace bv { b.clear_overflow_bits(m_tmp); while (mul_overflow_on_fixed(e, m_tmp)) { auto i = b.msb(m_tmp); - b.set(m_tmp, i, false); + m_tmp.set(i, false); } for (unsigned i = 0; i < a.nw; ++i) m_tmp2[i] = random_bits(); b.clear_overflow_bits(m_tmp2); while (b.bits() < m_tmp2) - b.set(m_tmp2, b.msb(m_tmp2), false); + m_tmp2.set(b.msb(m_tmp2), false); while (a.set_add(m_tmp3, m_tmp, m_tmp2)) - b.set(m_tmp2, b.msb(m_tmp2), false); + m_tmp2.set(b.msb(m_tmp2), false); return a.set_repair(true, m_tmp3); } else { @@ -1337,7 +1336,7 @@ namespace bv { a.clear_overflow_bits(m_tmp); // ensure r <= m while (a.bits() < m_tmp) - a.set(m_tmp, a.msb(m_tmp), false); + m_tmp.set(a.msb(m_tmp), false); a.set_sub(m_tmp2, a.bits(), m_tmp); set_div(m_tmp2, e.bits(), a.bw, m_tmp3, m_tmp4); return b.set_repair(random_bool(), m_tmp4); @@ -1372,14 +1371,14 @@ namespace bv { a.clear_overflow_bits(m_tmp); while (mul_overflow_on_fixed(b, m_tmp)) { auto i = b.msb(m_tmp); - b.set(m_tmp, i, false); + m_tmp.set(i, false); } while (true) { a.set_mul(m_tmp2, m_tmp, b.bits()); if (!add_overflow_on_fixed(e, m_tmp2)) break; auto i = b.msb(m_tmp); - b.set(m_tmp, i, false); + m_tmp.set(i, false); } a.set_add(m_tmp3, m_tmp2, e.bits()); return a.set_repair(random_bool(), m_tmp3); @@ -1419,11 +1418,10 @@ namespace bv { // a := rotate_right(e, n) n = (a.bw - n) % a.bw; for (unsigned i = a.bw - n; i < a.bw; ++i) - a.set(m_tmp, i + n - a.bw, e.get_bit(i)); + m_tmp.set(i + n - a.bw, e.get_bit(i)); for (unsigned i = 0; i < a.bw - n; ++i) - a.set(m_tmp, i + n, e.get_bit(i)); - a.set_repair(true, m_tmp); - return true; + m_tmp.set(i + n, e.get_bit(i)); + return a.set_repair(true, m_tmp); } bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i) { @@ -1436,8 +1434,7 @@ namespace bv { SASSERT(i == 1); unsigned sh = m_rand(b.bw); b.set(m_tmp, sh); - b.set_repair(random_bool(), m_tmp); - return true; + return b.set_repair(random_bool(), m_tmp); } } @@ -1491,13 +1488,13 @@ namespace bv { bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { for (unsigned i = 0; i < a.bw; ++i) - a.set(m_tmp, i, e.get_bit(i + b.bw)); + m_tmp.set(i, e.get_bit(i + b.bw)); a.clear_overflow_bits(m_tmp); return a.set_repair(random_bool(), m_tmp); } else { for (unsigned i = 0; i < b.bw; ++i) - b.set(m_tmp, i, e.get_bit(i)); + m_tmp.set(i, e.get_bit(i)); b.clear_overflow_bits(m_tmp); return b.set_repair(random_bool(), m_tmp); } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 0037bb5ca..770ad3223 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -111,7 +111,7 @@ namespace bv { else if (bv.is_bit2bool(e, s, idx)) { auto& val = wval0(s); val.try_set_bit(idx, !sign); - val.set(val.fixed, idx, true); + val.fixed.set(idx, true); val.init_fixed(); } } @@ -222,7 +222,7 @@ namespace bv { auto& v = ev.wval0(e); if (all_of(*e, [&](expr* arg) { return ev.is_fixed0(arg); })) { for (unsigned i = 0; i < v.bw; ++i) - v.set(v.fixed, i, true); + v.fixed.set(i, true); ev.m_fixed.setx(e->get_id(), true, false); return; } @@ -272,16 +272,16 @@ namespace bv { } bool pfixed = true; for (unsigned i = 0; i < v.bw; ++i) { - if (pfixed && a.get(a.fixed, i) && b.get(b.fixed, i)) - v.set(v.fixed, i, true); - else if (!pfixed && a.get(a.fixed, i) && b.get(b.fixed, i) && + if (pfixed && a.fixed.get(i) && b.fixed.get(i)) + v.fixed.set(i, true); + else if (!pfixed && a.fixed.get(i) && b.fixed.get(i) && !a.get_bit(i) && !b.get_bit(i)) { pfixed = true; - v.set(v.fixed, i, false); + v.fixed.set(i, false); } else { pfixed = false; - v.set(v.fixed, i, false); + v.fixed.set(i, false); } } @@ -294,36 +294,36 @@ namespace bv { // i'th bit depends on bits j + k = i // if the first j, resp k bits are 0, the bits j + k are 0 for (; j < v.bw; ++j) - if (!a.get(a.fixed, j)) + if (!a.fixed.get(j)) break; for (; k < v.bw; ++k) - if (!b.get(b.fixed, k)) + if (!b.fixed.get(k)) break; for (; zj < v.bw; ++zj) - if (!a.get(a.fixed, zj) || a.get_bit(zj)) + if (!a.fixed.get(zj) || a.get_bit(zj)) break; for (; zk < v.bw; ++zk) - if (!b.get(b.fixed, zk) || b.get_bit(zk)) + if (!b.fixed.get(zk) || b.get_bit(zk)) break; for (; hzj < v.bw; ++hzj) - if (!a.get(a.fixed, v.bw - hzj - 1) || a.get_bit(v.bw - hzj - 1)) + if (!a.fixed.get(v.bw - hzj - 1) || a.get_bit(v.bw - hzj - 1)) break; for (; hzk < v.bw; ++hzk) - if (!b.get(b.fixed, v.bw - hzk - 1) || b.get_bit(v.bw - hzk - 1)) + if (!b.fixed.get(v.bw - hzk - 1) || b.get_bit(v.bw - hzk - 1)) break; if (j > 0 && k > 0) { for (unsigned i = 0; i < std::min(k, j); ++i) { SASSERT(!v.get_bit(i)); - v.set(v.fixed, i, true); + v.fixed.set(i, true); } } // lower zj + jk bits are 0 if (zk > 0 || zj > 0) { for (unsigned i = 0; i < zk + zj; ++i) { SASSERT(!v.get_bit(i)); - v.set(v.fixed, i, true); + v.fixed.set(i, true); } } // upper bits are 0, if enough high order bits of a, b are 0. @@ -333,7 +333,7 @@ namespace bv { hzk = v.bw - hzk; for (unsigned i = hzj + hzk - 1; i < v.bw; ++i) { SASSERT(!v.get_bit(i)); - v.set(v.fixed, i, true); + v.fixed.set(i, true); } } break; @@ -342,9 +342,9 @@ namespace bv { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); for (unsigned i = 0; i < b.bw; ++i) - v.set(v.fixed, i, b.get(b.fixed, i)); + v.fixed.set(i, b.fixed.get(i)); for (unsigned i = 0; i < a.bw; ++i) - v.set(v.fixed, i + b.bw, a.get(a.fixed, i)); + v.fixed.set(i + b.bw, a.fixed.get(i)); break; } case OP_EXTRACT: { @@ -353,18 +353,18 @@ namespace bv { VERIFY(bv.is_extract(e, lo, hi, child)); auto& a = wval0(child); for (unsigned i = lo; i <= hi; ++i) - v.set(v.fixed, i - lo, a.get(a.fixed, i)); + v.fixed.set(i - lo, a.fixed.get(i)); break; } case OP_BNEG: { auto& a = wval0(e->get_arg(0)); bool pfixed = true; for (unsigned i = 0; i < v.bw; ++i) { - if (pfixed && a.get(a.fixed, i)) - v.set(v.fixed, i, true); + if (pfixed && a.fixed.get(i)) + v.fixed.set(i, true); else { pfixed = false; - v.set(v.fixed, i, false); + v.fixed.set(i, false); } } break; diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index a0a21a534..523bc99c4 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -31,60 +31,33 @@ namespace bv { reserve(nw + 1); } - void bvect::clear_overflow_bits() { - SASSERT(nw > 0); - (*this)[nw - 1] &= mask; - SASSERT(!has_overflow()); - } - - void bvect::set_sub(bvect const& a, bvect const& b) { - digit_t c; - mpn_manager().sub(a.data(), a.nw, b.data(), a.nw, data(), &c); - set_bw(bw); - clear_overflow_bits(); - } - bool operator==(bvect const& a, bvect const& b) { SASSERT(a.nw > 0); - SASSERT(!a.has_overflow()); - SASSERT(!b.has_overflow()); return 0 == mpn_manager().compare(a.data(), a.nw, b.data(), a.nw); } bool operator<(bvect const& a, bvect const& b) { - SASSERT(a.nw > 0); - SASSERT(!a.has_overflow()); - SASSERT(!b.has_overflow()); + SASSERT(a.nw > 0); return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) < 0; } bool operator>(bvect const& a, bvect const& b) { SASSERT(a.nw > 0); - SASSERT(!a.has_overflow()); - SASSERT(!b.has_overflow()); return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) > 0; } bool operator<=(bvect const& a, bvect const& b) { SASSERT(a.nw > 0); - SASSERT(!a.has_overflow()); - SASSERT(!b.has_overflow()); return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) <= 0; } bool operator>=(bvect const& a, bvect const& b) { SASSERT(a.nw > 0); - SASSERT(!a.has_overflow()); - SASSERT(!b.has_overflow()); return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) >= 0; } - - sls_valuation::sls_valuation(unsigned bw) : bw(bw) { - nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); - mask = (1 << (bw % (8 * sizeof(digit_t)))) - 1; - if (mask == 0) - mask = ~(digit_t)0; + sls_valuation::sls_valuation(unsigned bw) { + set_bw(bw); lo.set_bw(bw); hi.set_bw(bw); m_bits.set_bw(bw); @@ -92,8 +65,15 @@ namespace bv { // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated for (unsigned i = 0; i < nw; ++i) lo[i] = 0, hi[i] = 0, m_bits[i] = 0, fixed[i] = 0; - for (unsigned i = bw; i < 8 * sizeof(digit_t) * nw; ++i) - set(fixed, i, true); + fixed[nw - 1] = ~mask; + } + + void sls_valuation::set_bw(unsigned b) { + bw = b; + nw = (bw + sizeof(digit_t) * 8 - 1) / (8 * sizeof(digit_t)); + mask = (1 << (bw % (8 * sizeof(digit_t)))) - 1; + if (mask == 0) + mask = ~(digit_t)0; } bool sls_valuation::in_range(bvect const& bits) const { @@ -308,11 +288,11 @@ namespace bv { for (unsigned i = 0; i < bw; ++i) { if (p >= max_n) { for (unsigned j = i; j < bw; ++j) - if (get(d, j)) + if (d.get(j)) return max_n; return value; } - if (get(d, i)) + if (d.get(i)) value += p; p <<= 1; } @@ -322,7 +302,7 @@ namespace bv { void sls_valuation::shift_right(bvect& out, unsigned shift) const { SASSERT(shift < bw); for (unsigned i = 0; i < bw; ++i) - set(out, i, i + shift < bw ? get(m_bits, i + shift) : false); + out.set(i, i + shift < bw ? m_bits.get(i + shift) : false); SASSERT(well_formed()); } @@ -384,18 +364,18 @@ namespace bv { if (lo == hi) return; for (unsigned i = bw; i-- > 0; ) { - if (!get(fixed, i)) + if (!fixed.get(i)) continue; - if (get(m_bits, i) == get(lo, i)) + if (m_bits.get(i) == lo.get(i)) continue; - if (get(m_bits, i)) { - set(lo, i, true); + if (m_bits.get(i)) { + lo.set(i, true); for (unsigned j = i; j-- > 0; ) - set(lo, j, get(fixed, j) && get(m_bits, j)); + lo.set(j, fixed.get(j) && m_bits.get(j)); } else { for (unsigned j = bw; j-- > 0; ) - set(lo, j, get(fixed, j) && get(m_bits, j)); + lo.set(j, fixed.get(j) && m_bits.get(j)); } break; } @@ -406,18 +386,18 @@ namespace bv { mpn_manager().sub(hi.data(), nw, one.data(), nw, hi1.data(), &c); clear_overflow_bits(hi1); for (unsigned i = bw; i-- > 0; ) { - if (!get(fixed, i)) + if (!fixed.get(i)) continue; - if (get(m_bits, i) == get(hi1, i)) + if (m_bits.get(i) == hi1.get(i)) continue; - if (get(hi1, i)) { - set(hi1, i, false); + if (hi1.get(i)) { + hi1.set(i, false); for (unsigned j = i; j-- > 0; ) - set(hi1, j, !get(fixed, j) || get(m_bits, j)); + hi1.set(j, !fixed.get(j) || m_bits.get(j)); } else { for (unsigned j = bw; j-- > 0; ) - set(hi1, j, get(fixed, j) && get(m_bits, j)); + hi1.set(j, fixed.get(j) && m_bits.get(j)); } mpn_manager().add(hi1.data(), nw, one.data(), nw, hi.data(), nw + 1, &c); clear_overflow_bits(hi); @@ -426,16 +406,16 @@ namespace bv { // set fixed bits based on bounds auto set_fixed_bit = [&](unsigned i, bool b) { - if (!get(fixed, i)) { - set(fixed, i, true); - set(m_bits, i, b); + if (!fixed.get(i)) { + fixed.set(i, true); + m_bits.set(i, b); } }; // set most significant bits if (lo < hi) { unsigned i = bw; - for (; i-- > 0 && !get(hi, i); ) + for (; i-- > 0 && !hi.get(i); ) set_fixed_bit(i, false); if (is_power_of2(hi)) @@ -447,7 +427,7 @@ namespace bv { clear_overflow_bits(hi1); if (hi == hi1) { for (unsigned i = 0; i < bw; ++i) - set_fixed_bit(i, get(lo, i)); + set_fixed_bit(i, lo.get(i)); } SASSERT(well_formed()); } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 88b8efa59..c7852a82a 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -27,63 +27,22 @@ Author: namespace bv { - - class bvect : public svector { unsigned bw = 0; unsigned nw = 0; unsigned mask = 0; public: bvect() {} - bvect(unsigned sz): svector(sz, (unsigned)0) {} + bvect(unsigned sz) : svector(sz, (unsigned)0) {} void set_bw(unsigned bw); - void clear_overflow_bits(); - void set_sub(bvect const& a, bvect const& b); - - bool is_one() const { - SASSERT(bw > 0); - SASSERT(!has_overflow()); - for (unsigned i = 1; i < nw; ++i) - if (0 != (*this)[i]) - return false; - return 1 == (*this)[0]; - } - - bool is_ones() const { - SASSERT(bw > 0); - auto const& a = *this; - for (unsigned i = 0; i + 1 < nw; ++i) - if (0 != ~a[i]) - return false; - return ((~a[nw - 1]) & mask) == 0; - } - - bool is_zero() const { - SASSERT(bw > 0); - auto const& a = *this; - for (unsigned i = 0; i + 1 < nw; ++i) - if (a[i] != 0) - return false; - return (a[nw - 1] & mask) == 0; - } - - bool has_overflow() const { - SASSERT(bw > 0); - for (unsigned i = bw; i < nw * sizeof(digit_t) * 8; ++i) - if (get(i)) - return true; - return false; - } bool get(unsigned bit_idx) const { return (get_bit_word(bit_idx) & get_pos_mask(bit_idx)) != 0; } - unsigned parity() const { SASSERT(bw > 0); - SASSERT(!has_overflow()); for (unsigned i = 0; i < nw; ++i) if ((*this)[i] != 0) return (8 * sizeof(digit_t) * i) + trailing_zeros((*this)[i]); @@ -135,19 +94,26 @@ namespace bv { unsigned bw; // bit-width unsigned nw; // num words bvect fixed; // bit assignment and don't care bit + sls_valuation(unsigned bw); + void set_bw(unsigned bw); + unsigned num_bytes() const { return (bw + 7) / 8; } digit_t bits(unsigned i) const { return m_bits[i]; } bvect const& bits() const { return m_bits; } - bool get_bit(unsigned i) const { return get(m_bits, i); } + bool get_bit(unsigned i) const { return m_bits.get(i); } bool try_set_bit(unsigned i, bool b) { - if (get(fixed, i) && get_bit(i) != b) + SASSERT(in_range(m_bits)); + if (fixed.get(i) && get_bit(i) != b) return false; - set(m_bits, i, b); - return true; + m_bits.set(i, b); + if (in_range(m_bits)) + return true; + m_bits.set(i, !b); + return false; } void set_value(bvect& bits, rational const& r); @@ -161,24 +127,49 @@ namespace bv { bool has_range() const { return lo != hi; } void init_fixed(); - void clear_overflow_bits(bvect& bits) const { bits.clear_overflow_bits(); } + void clear_overflow_bits(bvect& bits) const { + SASSERT(nw > 0); + bits[nw - 1] &= mask; + SASSERT(!has_overflow(bits)); + } + bool in_range(bvect const& bits) const; bool can_set(bvect const& bits) const; bool eq(sls_valuation const& other) const { return eq(other.m_bits); } bool eq(bvect const& other) const { return other == m_bits; } - bool is_zero() const { return m_bits.is_zero(); } - bool is_zero(bvect const& a) const { return a.is_zero(); } + bool is_zero() const { return is_zero(m_bits); } + bool is_zero(bvect const& a) const { + SASSERT(!has_overflow(a)); + for (unsigned i = 0; i < nw; ++i) + if (a[i] != 0) + return false; + return true; + } - bool is_ones() const { return m_bits.is_ones(); } + bool is_ones() const { return is_ones(m_bits); } - bool is_one() const { return m_bits.is_one(); } - // bool is_one(bvect const& a) const { return a.is_one(); } + bool is_ones(bvect const& a) const { + SASSERT(!has_overflow(a)); + for (unsigned i = 0; i + 1 < nw; ++i) + if (0 != ~a[i]) + return false; + return 0 == (mask & ~a[nw - 1]); + } - bool sign() const { return get(m_bits, bw - 1); } + bool is_one() const { return is_one(m_bits); } + bool is_one(bvect const& a) const { + SASSERT(!has_overflow(a)); + for (unsigned i = 1; i < nw; ++i) + if (0 != a[i]) + return false; + return 1 == a[0]; + } - bool has_overflow(bvect const& bits) const { return bits.has_overflow(); } + bool sign() const { return m_bits.get(bw - 1); } + + bool has_overflow(bvect const& bits) const { return 0 != (bits[nw - 1] & ~mask); } unsigned parity(bvect const& bits) const { return bits.parity(); } @@ -227,12 +218,12 @@ namespace bv { void sub1(bvect& out) const { for (unsigned i = 0; i < bw; ++i) { - if (get(out, i)) { - set(out, i, false); + if (out.get(i)) { + out.set(i, false); return; } else - set(out, i, true); + out.set(i, true); } } @@ -243,11 +234,7 @@ namespace bv { void set_range(bvect& dst, unsigned lo, unsigned hi, bool b) { for (unsigned i = lo; i < hi; ++i) - set(dst, i, b); - } - - void set(bvect& d, unsigned bit_idx, bool val) const { - d.set(bit_idx, val); + dst.set(i, b); } void set(bvect& dst, unsigned v) const { @@ -261,14 +248,9 @@ namespace bv { dst[i] = src[i]; } - bool get(bvect const& d, unsigned bit_idx) const { - return d.get(bit_idx); - } - unsigned to_nat(unsigned max_n); std::ostream& display(std::ostream& out) const { - out << "V:"; out << std::hex; print_bits(out, m_bits); @@ -290,19 +272,13 @@ namespace bv { return !has_overflow(m_bits) && (!has_range() || in_range(m_bits)); } - private: - - - }; class sls_pre_valuation : public sls_valuation { public: - sls_pre_valuation(unsigned bw):sls_valuation(bw) {} + sls_pre_valuation(unsigned bw) :sls_valuation(bw) {} bvect& bits() { return m_bits; } - void set_bit(unsigned i, bool v) { set(m_bits, i, v); } - - + void set_bit(unsigned i, bool v) { m_bits.set(i, v); } }; inline std::ostream& operator<<(std::ostream& out, sls_valuation const& v) { return v.display(out); } From c451e4e50bfc6e1bbd5fd9f61b070463d1a7732a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2024 21:33:51 -0800 Subject: [PATCH 31/69] na --- src/ast/sls/bv_sls_fixed.cpp | 14 ++--- src/ast/sls/sls_valuation.cpp | 102 +++++++++++++++++----------------- src/ast/sls/sls_valuation.h | 14 ++--- 3 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 770ad3223..90899e802 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -260,16 +260,10 @@ namespace bv { auto& a = wval0(e->get_arg(0)); auto& b = wval0(e->get_arg(1)); rational r; - if (bv.is_numeral(e->get_arg(0), r) && b.has_range()) { - auto rlo = b.get_lo(); - auto rhi = b.get_hi(); - v.add_range(r + rlo, r + rhi); - } - if (bv.is_numeral(e->get_arg(1), r) && a.has_range()) { - auto rlo = a.get_lo(); - auto rhi = a.get_hi(); - v.add_range(r + rlo, r + rhi); - } + if (bv.is_numeral(e->get_arg(0), r) && b.has_range()) + v.add_range(r + b.lo(), r + b.hi()); + else if (bv.is_numeral(e->get_arg(1), r) && a.has_range()) + v.add_range(r + a.lo(), r + a.hi()); bool pfixed = true; for (unsigned i = 0; i < v.bw; ++i) { if (pfixed && a.fixed.get(i) && b.fixed.get(i)) diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 523bc99c4..2b4a5ef99 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -58,13 +58,13 @@ namespace bv { sls_valuation::sls_valuation(unsigned bw) { set_bw(bw); - lo.set_bw(bw); - hi.set_bw(bw); + m_lo.set_bw(bw); + m_hi.set_bw(bw); m_bits.set_bw(bw); fixed.set_bw(bw); // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated for (unsigned i = 0; i < nw; ++i) - lo[i] = 0, hi[i] = 0, m_bits[i] = 0, fixed[i] = 0; + m_lo[i] = 0, m_hi[i] = 0, m_bits[i] = 0, fixed[i] = 0; fixed[nw - 1] = ~mask; } @@ -78,7 +78,7 @@ namespace bv { bool sls_valuation::in_range(bvect const& bits) const { mpn_manager m; - auto c = m.compare(lo.data(), nw, hi.data(), nw); + auto c = m.compare(m_lo.data(), nw, m_hi.data(), nw); SASSERT(!has_overflow(bits)); // full range if (c == 0) @@ -86,12 +86,12 @@ namespace bv { // lo < hi: then lo <= bits & bits < hi if (c < 0) return - m.compare(lo.data(), nw, bits.data(), nw) <= 0 && - m.compare(bits.data(), nw, hi.data(), nw) < 0; + m.compare(m_lo.data(), nw, bits.data(), nw) <= 0 && + m.compare(bits.data(), nw, m_hi.data(), nw) < 0; // hi < lo: bits < hi or lo <= bits return - m.compare(lo.data(), nw, bits.data(), nw) <= 0 || - m.compare(bits.data(), nw, hi.data(), nw) < 0; + m.compare(m_lo.data(), nw, bits.data(), nw) <= 0 || + m.compare(bits.data(), nw, m_hi.data(), nw) < 0; } // @@ -170,29 +170,29 @@ namespace bv { } bool sls_valuation::round_up(bvect& dst) const { - if (lo < hi) { - if (hi <= dst) + if (m_lo < m_hi) { + if (m_hi <= dst) return false; - if (lo > dst) - set(dst, lo); + if (m_lo > dst) + set(dst, m_lo); } - else if (hi <= dst && lo > dst) - set(dst, lo); + else if (m_hi <= dst && m_lo > dst) + set(dst, m_lo); SASSERT(!has_overflow(dst)); return true; } bool sls_valuation::round_down(bvect& dst) const { - if (lo < hi) { - if (lo > dst) + if (m_lo < m_hi) { + if (m_lo > dst) return false; - if (hi <= dst) { - set(dst, hi); + if (m_hi <= dst) { + set(dst, m_hi); sub1(dst); } } - else if (hi <= dst && lo > dst) { - set(dst, hi); + else if (m_hi <= dst && m_lo > dst) { + set(dst, m_hi); sub1(dst); } SASSERT(well_formed()); @@ -214,9 +214,9 @@ namespace bv { } void sls_valuation::min_feasible(bvect& out) const { - if (lo < hi) { + if (m_lo < m_hi) { for (unsigned i = 0; i < nw; ++i) - out[i] = lo[i]; + out[i] = m_lo[i]; } else { for (unsigned i = 0; i < nw; ++i) @@ -226,9 +226,9 @@ namespace bv { } void sls_valuation::max_feasible(bvect& out) const { - if (lo < hi) { + if (m_lo < m_hi) { for (unsigned i = 0; i < nw; ++i) - out[i] = hi[i]; + out[i] = m_hi[i]; sub1(out); } else { @@ -315,35 +315,35 @@ namespace bv { SASSERT(is_zero(fixed)); // ranges can only be added before fixed bits are set. - if (lo == hi) { - set_value(lo, l); - set_value(hi, h); + if (m_lo == m_hi) { + set_value(m_lo, l); + set_value(m_hi, h); } else { - auto old_lo = get_value(lo); - auto old_hi = get_value(hi); + auto old_lo = get_value(m_lo); + auto old_hi = get_value(m_hi); if (old_lo < old_hi) { if (old_lo < l && l < old_hi) - set_value(lo, l), + set_value(m_lo, l), old_lo = l; if (old_hi < h && h < old_hi) - set_value(hi, h); + set_value(m_hi, h); } else { SASSERT(old_hi < old_lo); if (old_lo < l || l < old_hi) - set_value(lo, l), + set_value(m_lo, l), old_lo = l; if (old_lo < h && h < old_hi) - set_value(hi, h); + set_value(m_hi, h); else if (old_hi < old_lo && (h < old_hi || old_lo < h)) - set_value(hi, h); + set_value(m_hi, h); } } - SASSERT(!has_overflow(lo)); - SASSERT(!has_overflow(hi)); + SASSERT(!has_overflow(m_lo)); + SASSERT(!has_overflow(m_hi)); if (!in_range(m_bits)) - set(m_bits, lo); + set(m_bits, m_lo); SASSERT(well_formed()); } @@ -361,21 +361,21 @@ namespace bv { // lo < hi, set most significant bits based on hi // void sls_valuation::init_fixed() { - if (lo == hi) + if (m_lo == m_hi) return; for (unsigned i = bw; i-- > 0; ) { if (!fixed.get(i)) continue; - if (m_bits.get(i) == lo.get(i)) + if (m_bits.get(i) == m_lo.get(i)) continue; if (m_bits.get(i)) { - lo.set(i, true); + m_lo.set(i, true); for (unsigned j = i; j-- > 0; ) - lo.set(j, fixed.get(j) && m_bits.get(j)); + m_lo.set(j, fixed.get(j) && m_bits.get(j)); } else { for (unsigned j = bw; j-- > 0; ) - lo.set(j, fixed.get(j) && m_bits.get(j)); + m_lo.set(j, fixed.get(j) && m_bits.get(j)); } break; } @@ -383,7 +383,7 @@ namespace bv { bvect one(nw + 1); one[0] = 1; digit_t c; - mpn_manager().sub(hi.data(), nw, one.data(), nw, hi1.data(), &c); + mpn_manager().sub(m_hi.data(), nw, one.data(), nw, hi1.data(), &c); clear_overflow_bits(hi1); for (unsigned i = bw; i-- > 0; ) { if (!fixed.get(i)) @@ -399,8 +399,8 @@ namespace bv { for (unsigned j = bw; j-- > 0; ) hi1.set(j, fixed.get(j) && m_bits.get(j)); } - mpn_manager().add(hi1.data(), nw, one.data(), nw, hi.data(), nw + 1, &c); - clear_overflow_bits(hi); + mpn_manager().add(hi1.data(), nw, one.data(), nw, m_hi.data(), nw + 1, &c); + clear_overflow_bits(m_hi); break; } @@ -413,21 +413,21 @@ namespace bv { }; // set most significant bits - if (lo < hi) { + if (m_lo < m_hi) { unsigned i = bw; - for (; i-- > 0 && !hi.get(i); ) + for (; i-- > 0 && !m_hi.get(i); ) set_fixed_bit(i, false); - if (is_power_of2(hi)) + if (is_power_of2(m_hi)) set_fixed_bit(i, false); } // lo + 1 = hi: then bits = lo - mpn_manager().add(lo.data(), nw, one.data(), nw, hi1.data(), nw + 1, &c); + mpn_manager().add(m_lo.data(), nw, one.data(), nw, hi1.data(), nw + 1, &c); clear_overflow_bits(hi1); - if (hi == hi1) { + if (m_hi == hi1) { for (unsigned i = 0; i < bw; ++i) - set_fixed_bit(i, lo.get(i)); + set_fixed_bit(i, m_lo.get(i)); } SASSERT(well_formed()); } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index c7852a82a..33510a4dd 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -80,7 +80,7 @@ namespace bv { class sls_valuation { protected: bvect m_bits; - bvect lo, hi; // range assignment to bit-vector, as wrap-around interval + bvect m_lo, m_hi; // range assignment to bit-vector, as wrap-around interval unsigned mask; rational get_value(bvect const& bits) const; @@ -119,12 +119,12 @@ namespace bv { void set_value(bvect& bits, rational const& r); rational get_value() const { return get_value(m_bits); } - rational get_lo() const { return get_value(lo); } - rational get_hi() const { return get_value(hi); } + rational lo() const { return get_value(m_lo); } + rational hi() const { return get_value(m_hi); } void get(bvect& dst) const; void add_range(rational lo, rational hi); - bool has_range() const { return lo != hi; } + bool has_range() const { return m_lo != m_hi; } void init_fixed(); void clear_overflow_bits(bvect& bits) const { @@ -257,11 +257,11 @@ namespace bv { out << " fix:"; print_bits(out, fixed); - if (lo != hi) { + if (m_lo != m_hi) { out << " ["; - print_bits(out, lo); + print_bits(out, m_lo); out << ", "; - print_bits(out, hi); + print_bits(out, m_hi); out << "["; } out << std::dec; From 8f85df05edd24df573f108b27e6d888a4b270481 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Feb 2024 04:03:15 -0800 Subject: [PATCH 32/69] fb Signed-off-by: Nikolaj Bjorner --- src/test/sls_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp index 00ac0547c..8d242e67a 100644 --- a/src/test/sls_test.cpp +++ b/src/test/sls_test.cpp @@ -39,7 +39,7 @@ namespace bv { auto const& val = ev.wval0(e); rational n1, n2; - val.get_value(val.bits, n1); + n1 = val.get_value(); VERIFY(bv.is_numeral(r, n2)); if (n1 != n2) { @@ -167,7 +167,7 @@ namespace bv { auto& val1 = ev.wval0(e1); auto& val2 = ev.wval0(e2); if (!val1.eq(val2)) { - val2.set(val1.bits); + val2.set(val1.bits()); auto rep2 = ev.try_repair(to_app(e2), idx); if (!rep2) { verbose_stream() << "Not repaired " << mk_pp(e2, m) << "\n"; From a328366c7d0a533ac964080660b58ee63cbc1e1b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Feb 2024 19:05:16 -0800 Subject: [PATCH 33/69] move to single path mode for search Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 108 ++++++++++++++++++++++------------------- src/ast/sls/bv_sls.h | 7 +-- 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index e091eb4b5..bdc258462 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -43,17 +43,18 @@ namespace bv { } void sls::init_repair() { - m_repair_down.reset(); + m_repair_down = UINT_MAX; m_repair_up.reset(); + m_repair_roots.reset(); for (auto* e : m_terms.assertions()) { if (!m_eval.bval0(e)) { m_eval.set(e, true); - m_repair_down.insert(e->get_id()); + m_repair_roots.insert(e->get_id()); } } for (app* t : m_terms.terms()) if (t && !eval_is_correct(t)) - m_repair_down.insert(t->get_id()); + m_repair_roots.insert(t->get_id()); } void sls::reinit_eval() { @@ -78,15 +79,27 @@ namespace bv { std::pair sls::next_to_repair() { app* e = nullptr; - if (!m_repair_down.empty()) { - unsigned index = m_rand(m_repair_down.size()); - e = m_terms.term(m_repair_down.elem_at(index)); + if (m_repair_down != UINT_MAX) { + e = m_terms.term(m_repair_down); + m_repair_down = UINT_MAX; + return { true, e }; } - else if (!m_repair_up.empty()) { + + if (!m_repair_up.empty()) { + unsigned index = m_rand(m_repair_up.size()); + m_repair_up.remove(index); + e = m_terms.term(m_repair_up.elem_at(index)); + return { false, e }; + } + + if (!m_repair_roots.empty()) { unsigned index = m_rand(m_repair_up.size()); e = m_terms.term(m_repair_up.elem_at(index)); + m_repair_roots.remove(index); + return { true, e }; } - return { !m_repair_down.empty(), e }; + + return { false, nullptr }; } lbool sls::search() { @@ -97,35 +110,19 @@ namespace bv { auto [down, e] = next_to_repair(); if (!e) return l_true; - bool is_correct = eval_is_correct(e); - if (is_correct) { - if (down) - m_repair_down.remove(e->get_id()); - else - m_repair_up.remove(e->get_id()); - } - else { - IF_VERBOSE(20, verbose_stream() << (down ? "d #" : "u #") - << e->get_id() << ": " - << mk_bounded_pp(e, m, 1) << " "; - if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e) << " " << (m_eval.is_fixed0(e)?"fixed ":" "); - if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " "; - verbose_stream() << "\n"); - if (down) - try_repair_down(e); - else - try_repair_up(e); - } + if (eval_is_correct(e)) + continue; + + trace_repair(down, e); + + if (down) + try_repair_down(e); + else + try_repair_up(e); } return l_undef; } - void sls::trace() { - IF_VERBOSE(2, verbose_stream() - << "(bvsls :restarts " << m_stats.m_restarts - << " :repair-down " << m_repair_down.size() - << " :repair-up " << m_repair_up.size() << ")\n"); - } lbool sls::operator()() { lbool res = l_undef; @@ -147,29 +144,21 @@ namespace bv { unsigned n = e->get_num_args(); if (n > 0) { unsigned s = m_rand(n); - for (unsigned i = 0; i < n; ++i) - if (try_repair_down(e, (i + s) % n)) + for (unsigned i = 0; i < n; ++i) { + auto j = (i + s) % n; + if (m_eval.try_repair(e, j)) { + set_repair_down(e->get_arg(j)); return; + } + } } - m_repair_down.remove(e->get_id()); m_repair_up.insert(e->get_id()); } - bool sls::try_repair_down(app* e, unsigned i) { - expr* child = e->get_arg(i); - bool was_repaired = m_eval.try_repair(e, i); - if (was_repaired) { - m_repair_down.insert(child->get_id()); - for (auto p : m_terms.parents(child)) - m_repair_up.insert(p->get_id()); - } - return was_repaired; - } - void sls::try_repair_up(app* e) { - m_repair_up.remove(e->get_id()); + if (m_terms.is_assertion(e) || !m_eval.repair_up(e)) - m_repair_down.insert(e->get_id()); + m_repair_roots.insert(e->get_id()); else { if (!eval_is_correct(e)) { verbose_stream() << "incorrect eval #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; @@ -225,10 +214,10 @@ namespace bv { out << e->get_id() << ": " << mk_bounded_pp(e, m, 1) << " "; if (m_eval.is_fixed0(e)) out << "f "; - if (m_repair_down.contains(e->get_id())) - out << "d "; if (m_repair_up.contains(e->get_id())) out << "u "; + if (m_repair_roots.contains(e->get_id())) + out << "r "; if (bv.is_bv(e)) out << m_eval.wval0(e); else if (m.is_bool(e)) @@ -244,4 +233,21 @@ namespace bv { m_config.m_max_restarts = p.max_restarts(); m_rand.set_seed(p.random_seed()); } + + void sls::trace_repair(bool down, expr* e) { + IF_VERBOSE(20, + verbose_stream() << (down ? "d #" : "u #") + << e->get_id() << ": " + << mk_bounded_pp(e, m, 1) << " "; + if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e) << " " << (m_eval.is_fixed0(e) ? "fixed " : " "); + if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " "; + verbose_stream() << "\n"); + } + + void sls::trace() { + IF_VERBOSE(2, verbose_stream() + << "(bvsls :restarts " << m_stats.m_restarts + << " :repair-up " << m_repair_up.size() + << " :repair-roots " << m_repair_roots.size() << ")\n"); + } } diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index be2e8feed..d92f991db 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -44,7 +44,8 @@ namespace bv { sls_terms m_terms; sls_eval m_eval; sls_stats m_stats; - indexed_uint_set m_repair_down, m_repair_up; + indexed_uint_set m_repair_up, m_repair_roots; + unsigned m_repair_down = UINT_MAX; ptr_vector m_todo; random_gen m_rand; config m_config; @@ -54,13 +55,13 @@ namespace bv { bool eval_is_correct(app* e); void try_repair_down(app* e); void try_repair_up(app* e); - - bool try_repair_down(app* e, unsigned i); + void set_repair_down(expr* e) { m_repair_down = e->get_id(); } lbool search(); void reinit_eval(); void init_repair(); void trace(); + void trace_repair(bool down, expr* e); public: sls(ast_manager& m); From 0e5b504c309f189af0840c3bce3071046396df71 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Feb 2024 01:38:18 -0800 Subject: [PATCH 34/69] remove bw setting --- src/ast/sls/sls_valuation.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 2b4a5ef99..a964af2f2 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -436,7 +436,6 @@ namespace bv { digit_t c; mpn_manager().sub(a.data(), nw, b.data(), nw, out.data(), &c); clear_overflow_bits(out); - out.set_bw(bw); } bool sls_valuation::set_add(bvect& out, bvect const& a, bvect const& b) const { @@ -444,7 +443,6 @@ namespace bv { mpn_manager().add(a.data(), nw, b.data(), nw, out.data(), nw + 1, &c); bool ovfl = out[nw] != 0 || has_overflow(out); clear_overflow_bits(out); - out.set_bw(bw); return ovfl; } @@ -457,7 +455,6 @@ namespace bv { ovfl |= out[i] != 0; } clear_overflow_bits(out); - out.set_bw(bw); return ovfl; } From 58474df4381b0102a68d778a8a9e1dd0c6253883 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Feb 2024 14:34:28 -0800 Subject: [PATCH 35/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls_eval.cpp | 150 +++++++++++++++++++++------------- src/ast/sls/bv_sls_eval.h | 8 ++ src/ast/sls/sls_valuation.cpp | 51 ++++++++++++ src/ast/sls/sls_valuation.h | 16 ++++ 4 files changed, 170 insertions(+), 55 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 5a26dc55b..2535cf4e3 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -686,10 +686,7 @@ namespace bv { } digit_t sls_eval::random_bits() { - digit_t r = 0; - for (digit_t i = 0; i < sizeof(digit_t); ++i) - r ^= m_rand() << (8 * i); - return r; + return sls_valuation::random_bits(m_rand); } bool sls_eval::try_repair(app* e, unsigned i) { @@ -826,7 +823,7 @@ namespace bv { case OP_ZERO_EXT: return try_repair_zero_ext(wval0(e), wval0(e, 0)); case OP_SIGN_EXT: - return try_repair_zero_ext(wval0(e), wval0(e, 0)); + return try_repair_sign_ext(wval0(e), wval0(e, 0)); case OP_CONCAT: return try_repair_concat(wval0(e), wval0(e, 0), wval0(e, 1), i); case OP_EXTRACT: { @@ -886,33 +883,33 @@ namespace bv { bool sls_eval::try_repair_eq(app* e, unsigned i) { auto child = e->get_arg(i); - auto ev = bval0(e); + auto is_true = bval0(e); if (m.is_bool(child)) { SASSERT(!is_fixed0(child)); auto bv = bval0(e->get_arg(1 - i)); - m_eval[child->get_id()] = ev == bv; + m_eval[child->get_id()] = is_true == bv; return true; } else if (bv.is_bv(child)) { auto & a = wval0(e->get_arg(i)); auto & b = wval0(e->get_arg(1 - i)); - if (ev) + if (is_true) return a.try_set(b.bits()); else { - // pick random bit to differ - a.get(m_tmp); - unsigned start = m_rand(a.bw); - for (unsigned idx = 0; idx < a.bw; ++idx) { - unsigned j = (idx + start) % a.bw; - if (!a.fixed.get(j)) { - m_tmp.set(idx, !b.get_bit(j)); - bool r = a.try_set(m_tmp); - if (r) - return true; - m_tmp.set(j, b.get_bit(j)); - } + bool try_above = m_rand() % 2 == 0; + if (try_above) { + a.set_add(m_tmp, b.bits(), m_one); + if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) + return true; + } + a.set_sub(m_tmp, b.bits(), m_one); + if (!a.is_zero(m_tmp) && a.set_random_at_most(m_tmp, m_tmp2, m_rand)) + return true; + if (!try_above) { + a.set_add(m_tmp, b.bits(), m_one); + if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) + return true; } - // could be due to bounds? return false; } } @@ -1144,6 +1141,18 @@ namespace bv { // a <=s b <-> a + p2 <=u b + p2 + // + // to solve x for x <=s b: + // y := at most (b + p2) - p2 + // x := random_at_most y + // or + // x := random_at_least y - p2 if y < p2 + // + // to solve x for x >s b: + // infeasible if b + p2 = 0 + // y := at least (b + 1 + p2) - p2 + // TODO + // bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { a.set(m_tmp, b.bits()); if (e) { @@ -1175,33 +1184,30 @@ namespace bv { bool sls_eval::try_repair_ule(bool e, bvval& a, bvect const& t) { if (e) { - if (!a.get_at_most(t, m_tmp)) - return false; + // a <= t + return a.set_random_at_most(t, m_tmp, m_rand); } else { - // a > b - a.set_add(m_tmp2, t, m_one); - if (a.is_zero(m_tmp2)) - return false; - if (!a.get_at_least(m_tmp2, m_tmp)) - return false; - } - return a.set_repair(random_bool(), m_tmp); + // a > t + a.set_add(m_tmp, t, m_one); + if (a.is_zero(m_tmp)) + return false; + return a.set_random_at_least(m_tmp, m_tmp2, m_rand); + } } bool sls_eval::try_repair_uge(bool e, bvval& a, bvect const& t) { if (e) { - if (!a.get_at_least(t, m_tmp)) - return false; + // a >= t + return a.set_random_at_least(t, m_tmp, m_rand); } else { + // a < t if (a.is_zero(t)) return false; - a.set_sub(m_tmp2, t, m_one); - if (!a.get_at_most(m_tmp2, m_tmp)) - return false; - } - return a.set_repair(random_bool(), m_tmp); + a.set_sub(m_tmp, t, m_one); + return a.set_random_at_most(m_tmp, m_tmp2, m_rand); + } } bool sls_eval::try_repair_bit2bool(bvval& a, unsigned idx) { @@ -1300,13 +1306,12 @@ namespace bv { return a.set_repair(false, m_tmp); } // b * e + r = a - for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = (random_bits() & ~b.fixed[i]) | (b.fixed[i] & b.bits()[i]); - b.clear_overflow_bits(m_tmp); + b.get_variant(m_tmp, m_rand); while (mul_overflow_on_fixed(e, m_tmp)) { auto i = b.msb(m_tmp); m_tmp.set(i, false); } + for (unsigned i = 0; i < a.nw; ++i) m_tmp2[i] = random_bits(); b.clear_overflow_bits(m_tmp2); @@ -1477,35 +1482,70 @@ namespace bv { } } - bool sls_eval::try_repair_zero_ext(bvval const& e, bvval& a) { - bool change = false; - for (unsigned i = 0; i < a.bw; ++i) - if (a.try_set_bit(i, e.get_bit(i))) - change = true; - return change; + // + // prefix of e must be 1s or 0 and match bit position of last bit in a. + // set a to suffix of e, matching signs. + // + bool sls_eval::try_repair_sign_ext(bvval const& e, bvval& a) { + for (unsigned i = a.bw; i < e.bw; ++i) + if (e.get_bit(i) != e.get_bit(a.bw - 1)) + return false; + e.get(m_tmp); + a.clear_overflow_bits(m_tmp); + return a.try_set(m_tmp); } - bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i) { - if (i == 0) { + // + // prefix of e must be 0s. + // + bool sls_eval::try_repair_zero_ext(bvval const& e, bvval& a) { + for (unsigned i = a.bw; i < e.bw; ++i) + if (e.get_bit(i)) + return false; + e.get(m_tmp); + a.clear_overflow_bits(m_tmp); + return a.try_set(m_tmp); + } + + bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned idx) { + if (idx == 0) { for (unsigned i = 0; i < a.bw; ++i) m_tmp.set(i, e.get_bit(i + b.bw)); a.clear_overflow_bits(m_tmp); - return a.set_repair(random_bool(), m_tmp); + return a.try_set(m_tmp); } else { for (unsigned i = 0; i < b.bw; ++i) m_tmp.set(i, e.get_bit(i)); b.clear_overflow_bits(m_tmp); - return b.set_repair(random_bool(), m_tmp); + return b.try_set(m_tmp); } } + // + // e = a[hi:lo], where hi = e.bw + lo - 1 + // for the randomized assignment, + // set a outside of [hi:lo] to random values with preference to 0 or 1 bits + // bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { - bool change = false; + if (m_rand() % m_config.m_prob_randomize_extract <= 100) { + a.get_variant(m_tmp, m_rand); + if (0 == (m_rand() % 2)) { + auto bit = 0 == (m_rand() % 2); + if (!a.try_set_range(m_tmp, 0, lo, bit)) + a.try_set_range(m_tmp, 0, lo, !bit); + } + if (0 == (m_rand() % 2)) { + auto bit = 0 == (m_rand() % 2); + if (!a.try_set_range(m_tmp, lo + e.bw, a.bw, bit)) + a.try_set_range(m_tmp, lo + e.bw, a.bw, !bit); + } + } + else + a.get(m_tmp); for (unsigned i = 0; i < e.bw; ++i) - if (a.try_set_bit(i + lo, e.get_bit(i))) - change = true; - return change; + m_tmp.set(i + lo, e.get_bit(i)); + return a.try_set(m_tmp); } void sls_eval::set_div(bvect const& a, bvect const& b, unsigned bw, diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index b379f7e85..47efdf06b 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -26,6 +26,10 @@ namespace bv { class sls_fixed; class sls_eval { + struct config { + unsigned m_prob_randomize_extract = 50; + }; + friend class sls_fixed; friend class sls_test; ast_manager& m; @@ -34,6 +38,9 @@ namespace bv { mutable mpn_manager mpn; ptr_vector m_todo; random_gen m_rand; + config m_config; + + scoped_ptr_vector m_values0; // expr-id -> bv valuation scoped_ptr_vector m_values1; // expr-id -> bv valuation @@ -95,6 +102,7 @@ namespace bv { bool try_repair_uge(bool e, bvval& a, bvect const& t); bool try_repair_umul_ovfl(bool e, bvval& a, bvval& b, unsigned i); bool try_repair_zero_ext(bvval const& e, bvval& a); + bool try_repair_sign_ext(bvval const& e, bvval& a); bool try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_extract(bvval const& e, bvval& a, unsigned lo); void add_p2_1(bvval const& a, bvect& t) const; diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index a964af2f2..9d7f60407 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -199,6 +199,44 @@ namespace bv { return true; } + bool sls_valuation::set_random_at_most(bvect const& src, bvect& tmp, random_gen& r) { + if (!get_at_most(src, tmp)) + return false; + if (is_zero(tmp) || (0 == r() % 2)) + return try_set(tmp); + + + // random value below tmp + auto msb_bit = msb(tmp); + for (unsigned i = 0; i < nw; ++i) + tmp[i] = (random_bits(r) & ~fixed[i]) | (fixed[i] & tmp[i]); + for (unsigned i = msb_bit; i < bw; ++i) + tmp.set(i, false); + if (m_lo == m_hi || is_zero(m_lo) || m_lo <= tmp) + return try_set(tmp); + + // for simplicity, bail out if we were not lucky + return get_at_most(src, tmp) && try_set(tmp); + } + + bool sls_valuation::set_random_at_least(bvect const& src, bvect& tmp, random_gen& r) { + if (!get_at_least(src, tmp)) + return false; + if (is_ones(tmp) || (0 == r() % 2)) + return try_set(tmp); + + // random value at least tmp + auto msb_bit = msb(tmp); + for (unsigned i = 0; i < nw; ++i) + tmp[i] = (random_bits(r) & ~fixed[i]) | (fixed[i] & tmp[i]); + tmp.set(msb_bit, true); + if (m_lo == m_hi || is_zero(m_hi) || m_hi > tmp) + return try_set(tmp); + + // for simplicity, bail out if we were not lucky + return get_at_least(src, tmp) && try_set(tmp); + } + bool sls_valuation::set_repair(bool try_down, bvect& dst) { for (unsigned i = 0; i < nw; ++i) dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); @@ -266,6 +304,19 @@ namespace bv { dst[i] = m_bits[i]; } + digit_t sls_valuation::random_bits(random_gen& rand) { + digit_t r = 0; + for (digit_t i = 0; i < sizeof(digit_t); ++i) + r ^= rand() << (8 * i); + return r; + } + + void sls_valuation::get_variant(bvect& dst, random_gen& r) const { + for (unsigned i = 0; i < nw; ++i) + dst[i] = (random_bits(r) & ~fixed[i]) | (fixed[i] & m_bits[i]); + clear_overflow_bits(dst); + } + // // new_bits != bits => ~fixed // 0 = (new_bits ^ bits) & fixed diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 33510a4dd..17b92efda 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -186,8 +186,15 @@ namespace bv { bool get_at_most(bvect const& src, bvect& dst) const; bool get_at_least(bvect const& src, bvect& dst) const; + bool set_random_at_most(bvect const& src, bvect& tmp, random_gen& r); + bool set_random_at_least(bvect const& src, bvect& tmp, random_gen& r); + bool set_repair(bool try_down, bvect& dst); + + static digit_t random_bits(random_gen& r); + void get_variant(bvect& dst, random_gen& r) const; + bool try_set(bvect const& src) { if (!can_set(src)) return false; @@ -237,6 +244,15 @@ namespace bv { dst.set(i, b); } + bool try_set_range(bvect& dst, unsigned lo, unsigned hi, bool b) { + for (unsigned i = lo; i < hi; ++i) + if (fixed.get(i) && get_bit(i) != b) + return false; + for (unsigned i = lo; i < hi; ++i) + dst.set(i, b); + return true; + } + void set(bvect& dst, unsigned v) const { dst[0] = v; for (unsigned i = 1; i < nw; ++i) From 2590d672f464d96c5777331237e8dcc8dc5c537c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Feb 2024 20:06:17 -0800 Subject: [PATCH 36/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls_eval.cpp | 148 ++++++++++++++++++++++++---------- src/ast/sls/bv_sls_eval.h | 2 + src/ast/sls/sls_valuation.cpp | 79 +++++++++++++++--- src/ast/sls/sls_valuation.h | 5 ++ 4 files changed, 183 insertions(+), 51 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 2535cf4e3..eeaecc0f3 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -1122,57 +1122,123 @@ namespace bv { for (unsigned i = 0; i < e.nw; ++i) m_tmp[i] = ~e.bits()[i]; a.clear_overflow_bits(m_tmp); - return a.set_repair(random_bool(), m_tmp); + return a.try_set(m_tmp); } - bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { - + bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { e.set_sub(m_tmp, m_zero, e.bits()); - return a.set_repair(random_bool(), m_tmp); + return a.try_set(m_tmp); } - bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { - return try_repair_ule(e, a, b.bits()); - } - - bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) { - return try_repair_uge(e, a, b.bits()); - } // a <=s b <-> a + p2 <=u b + p2 - // - // to solve x for x <=s b: - // y := at most (b + p2) - p2 - // x := random_at_most y - // or - // x := random_at_least y - p2 if y < p2 - // + // NB: p2 = -p2 + // // to solve x for x >s b: - // infeasible if b + p2 = 0 - // y := at least (b + 1 + p2) - p2 - // TODO + // infeasible if b + 1 = p2 + // solve for x >=s b + 1 // bool sls_eval::try_repair_sle(bool e, bvval& a, bvval const& b) { - a.set(m_tmp, b.bits()); - if (e) { - return a.set_repair(true, m_tmp); - } + auto& p2 = m_b; + b.set_zero(p2); + p2.set(b.bw - 1, true); + p2.set_bw(b.bw); + bool r = false; + if (e) + r = try_repair_sle(a, b.bits(), p2); else { - a.set_add(m_tmp2, m_tmp, m_one); - return a.set_repair(false, m_tmp2); + auto& b1 = m_nexta; + a.set_add(b1, b.bits(), m_one); + if (p2 == b1) + r = false; + else + r = try_repair_sge(a, b1, p2); } + p2.set_bw(0); + return r; } + // to solve x for x = p2 if c >= p2 (b < p2) + // or + // x := random p2 <= x <= b if c < p2 (b >= p2) + // + bool sls_eval::try_repair_sle(bvval& a, bvect const& b, bvect const& p2) { + bool r = false; + if (b < p2) { + bool coin = m_rand() % 2 == 0; + if (coin) + r = a.set_random_at_least(p2, m_tmp3, m_rand); + if (!r) + r = a.set_random_at_most(b, m_tmp3, m_rand); + if (!coin && !r) + r = a.set_random_at_least(p2, m_tmp3, m_rand); + } + else + r = a.set_random_in_range(p2, b, m_tmp3, m_rand); + return r; + } + + // solve for x >=s b + // + // d := b + p2 + // + // x := random b <= x < p2 if d >= p2 (b < p2) + // or + // x := random b <= x or x < p2 if d < p2 + // + + bool sls_eval::try_repair_sge(bvval& a, bvect const& b, bvect const& p2) { + auto& p2_1 = m_tmp4; + a.set_sub(p2_1, p2, m_one); + p2_1.set_bw(a.bw); + bool r = false; + if (b < p2) + // random b <= x < p2 + r = a.set_random_in_range(b, p2_1, m_tmp3, m_rand); + else { + // random b <= x or x < p2 + bool coin = m_rand() % 2 == 0; + if (coin) + r = a.set_random_at_most(p2_1, m_tmp3, m_rand); + if (!r) + r = a.set_random_at_least(b, m_tmp3, m_rand); + if (!r && !coin) + r = a.set_random_at_most(p2_1, m_tmp3, m_rand); + } + p2_1.set_bw(0); + return r; } void sls_eval::add_p2_1(bvval const& a, bvect& t) const { @@ -1182,30 +1248,30 @@ namespace bv { a.clear_overflow_bits(t); } - bool sls_eval::try_repair_ule(bool e, bvval& a, bvect const& t) { + bool sls_eval::try_repair_ule(bool e, bvval& a, bvval const& b) { if (e) { // a <= t - return a.set_random_at_most(t, m_tmp, m_rand); + return a.set_random_at_most(b.bits(), m_tmp, m_rand); } else { // a > t - a.set_add(m_tmp, t, m_one); + a.set_add(m_tmp, b.bits(), m_one); if (a.is_zero(m_tmp)) return false; return a.set_random_at_least(m_tmp, m_tmp2, m_rand); } } - bool sls_eval::try_repair_uge(bool e, bvval& a, bvect const& t) { + bool sls_eval::try_repair_uge(bool e, bvval& a, bvval const& b) { if (e) { // a >= t - return a.set_random_at_least(t, m_tmp, m_rand); + return a.set_random_at_least(b.bits(), m_tmp, m_rand); } else { // a < t - if (a.is_zero(t)) + if (b.is_zero()) return false; - a.set_sub(m_tmp, t, m_one); + a.set_sub(m_tmp, b.bits(), m_one); return a.set_random_at_most(m_tmp, m_tmp2, m_rand); } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 47efdf06b..7798562d5 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -89,6 +89,8 @@ namespace bv { bool try_repair_uge(bool e, bvval& a, bvval const& b); bool try_repair_sle(bool e, bvval& a, bvval const& b); bool try_repair_sge(bool e, bvval& a, bvval const& b); + bool try_repair_sge(bvval& a, bvect const& b, bvect const& p2); + bool try_repair_sle(bvval& a, bvect const& b, bvect const& p2); bool try_repair_shl(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_ashr(bvval const& e, bvval& a, bvval& b, unsigned i); bool try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i); diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 9d7f60407..33f9c4452 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -205,13 +205,9 @@ namespace bv { if (is_zero(tmp) || (0 == r() % 2)) return try_set(tmp); - + set_random_below(tmp, r); // random value below tmp - auto msb_bit = msb(tmp); - for (unsigned i = 0; i < nw; ++i) - tmp[i] = (random_bits(r) & ~fixed[i]) | (fixed[i] & tmp[i]); - for (unsigned i = msb_bit; i < bw; ++i) - tmp.set(i, false); + if (m_lo == m_hi || is_zero(m_lo) || m_lo <= tmp) return try_set(tmp); @@ -226,10 +222,8 @@ namespace bv { return try_set(tmp); // random value at least tmp - auto msb_bit = msb(tmp); - for (unsigned i = 0; i < nw; ++i) - tmp[i] = (random_bits(r) & ~fixed[i]) | (fixed[i] & tmp[i]); - tmp.set(msb_bit, true); + set_random_above(tmp, r); + if (m_lo == m_hi || is_zero(m_hi) || m_hi > tmp) return try_set(tmp); @@ -237,6 +231,71 @@ namespace bv { return get_at_least(src, tmp) && try_set(tmp); } + bool sls_valuation::set_random_in_range(bvect const& lo, bvect const& hi, bvect& tmp, random_gen& r) { + if (0 == r() % 2) { + if (!get_at_least(lo, tmp)) + return false; + SASSERT(in_range(tmp)); + if (hi < tmp) + return false; + + if (is_ones(tmp) || (0 == r() % 2)) + return try_set(tmp); + set_random_above(tmp, r); + round_down(tmp, [&](bvect const& t) { return hi >= t && in_range(t); }); + if (in_range(tmp) && lo <= tmp && hi >= tmp) + return try_set(tmp); + return get_at_least(lo, tmp) && hi >= tmp && try_set(tmp); + } + else { + if (!get_at_most(hi, tmp)) + return false; + SASSERT(in_range(tmp)); + if (lo > tmp) + return false; + if (is_zero(tmp) || (0 == r() % 2)) + return try_set(tmp); + set_random_below(tmp, r); + round_up(tmp, [&](bvect const& t) { return lo <= t && in_range(t); }); + if (in_range(tmp) && lo <= tmp && hi >= tmp) + return try_set(tmp); + return get_at_most(hi, tmp) && lo <= tmp && try_set(tmp); + } + } + + void sls_valuation::round_down(bvect& dst, std::function const& is_feasible) { + for (unsigned i = bw; !is_feasible(dst) && i-- > 0; ) + if (!fixed.get(i) && dst.get(i)) + dst.set(i, false); + } + + void sls_valuation::round_up(bvect& dst, std::function const& is_feasible) { + for (unsigned i = 0; !is_feasible(dst) && i < bw; ++i) + if (!fixed.get(i) && !dst.get(i)) + dst.set(i, true); + } + + void sls_valuation::set_random_above(bvect& dst, random_gen& r) { + for (unsigned i = 0; i < nw; ++i) + dst[i] = dst[i] | (random_bits(r) & ~fixed[i]); + } + + void sls_valuation::set_random_below(bvect& dst, random_gen& r) { + if (is_zero(dst)) + return; + unsigned n = 0, idx = UINT_MAX; + for (unsigned i = 0; i < bw; ++i) + if (dst.get(i) && !fixed.get(i) && (r() % ++n) == 0) + idx = i; + + if (idx == UINT_MAX) + return; + dst.set(idx, false); + for (unsigned i = 0; i < idx; ++i) + if (!fixed.get(i)) + dst.set(i, r() % 2 == 0); + } + bool sls_valuation::set_repair(bool try_down, bvect& dst) { for (unsigned i = 0; i < nw; ++i) dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 17b92efda..9f199bb6d 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -188,8 +188,13 @@ namespace bv { bool set_random_at_most(bvect const& src, bvect& tmp, random_gen& r); bool set_random_at_least(bvect const& src, bvect& tmp, random_gen& r); + bool set_random_in_range(bvect const& lo, bvect const& hi, bvect& tmp, random_gen& r); bool set_repair(bool try_down, bvect& dst); + void set_random_above(bvect& dst, random_gen& r); + void set_random_below(bvect& dst, random_gen& r); + void round_down(bvect& dst, std::function const& is_feasible); + void round_up(bvect& dst, std::function const& is_feasible); static digit_t random_bits(random_gen& r); From 8f139e862c5a22d59ebc8f0127e1105c7ba04e0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Feb 2024 08:16:12 -0800 Subject: [PATCH 37/69] updates to multiplication --- src/ast/sls/bv_sls_eval.cpp | 75 ++++++++++++++----------------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index eeaecc0f3..9d0246d49 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -989,23 +989,30 @@ namespace bv { } + // + // first try to set a := e - b + // If this fails, set a to a random value + // bool sls_eval::try_repair_add(bvval const& e, bvval& a, bvval const& b) { a.set_sub(m_tmp, e.bits(), b.bits()); - return a.set_repair(random_bool(), m_tmp); + if (a.try_set(m_tmp)) + return true; + a.get_variant(m_tmp, m_rand); + return a.set_repair(random_bool(), m_tmp); } - bool sls_eval::try_repair_sub(bvval const& e, bvval& a, bvval & b, unsigned i) { - if (i == 0) { + if (i == 0) // e = a - b -> a := e + b - a.set_add(m_tmp, e.bits(), b.bits()); - return a.set_repair(random_bool(), m_tmp); - } - else { + a.set_add(m_tmp, e.bits(), b.bits()); + else // b := a - e - b.set_sub(m_tmp, a.bits(), e.bits()); - return b.set_repair(random_bool(), m_tmp); - } + b.set_sub(m_tmp, a.bits(), e.bits()); + if (a.try_set(m_tmp)) + return true; + // fall back to a random value + a.get_variant(m_tmp, m_rand); + return a.set_repair(random_bool(), m_tmp); } /** @@ -1013,19 +1020,15 @@ namespace bv { * 8*e = a*(2b), then a = 4e*b^-1 */ bool sls_eval::try_repair_mul(bvval const& e, bvval& a, bvval const& b) { - if (b.is_zero()) { - if (a.is_zero()) { - a.set(m_tmp, 1); - return a.try_set(m_tmp); - } - verbose_stream() << "cannot repair 0\n"; - return false; - } - unsigned parity_e = e.parity(e.bits()); unsigned parity_b = b.parity(b.bits()); -#if 1 + if (e.is_zero()) { + a.get_variant(m_tmp, m_rand); + for (unsigned i = 0; i < e.bw - parity_b; ++i) + m_tmp.set(i, false); + return a.set_repair(random_bool(), m_tmp); + } auto& x = m_tmp; auto& y = m_tmp2; @@ -1041,8 +1044,11 @@ namespace bv { // x*ta + y*tb = x b.get(y); - if (parity_b > 0) + if (parity_b > 0) { b.shift_right(y, parity_b); + for (unsigned i = parity_b; i < e.bw; ++i) + y.set(i, m_rand() % 2 == 0); + } y[a.nw] = 0; x[a.nw] = 0; @@ -1084,38 +1090,13 @@ namespace bv { if (parity_b > 0) b.shift_right(y, parity_b); a.set_mul(m_tmp, tb, y); -#if 0 - for (unsigned i = a.nw; i-- > 0; ) - verbose_stream() << tb[i]; - verbose_stream() << "\n"; - for (unsigned i = a.nw; i-- > 0; ) - verbose_stream() << y[i]; - verbose_stream() << "\n"; - for (unsigned i = a.nw; i-- > 0; ) - verbose_stream() << m_tmp[i]; - verbose_stream() << "\n"; -#endif SASSERT(a.is_one(m_tmp)); #endif e.get(m_tmp2); if (parity_e > 0 && parity_b > 0) b.shift_right(m_tmp2, std::min(parity_b, parity_e)); a.set_mul(m_tmp, tb, m_tmp2); - return a.set_repair(random_bool(), m_tmp); - -#else - - rational ne, nb; - e.get_value(e.bits, ne); - b.get_value(b.bits, nb); - - if (parity_b > 0) - ne /= rational::power_of_two(std::min(parity_b, parity_e)); - auto inv_b = nb.pseudo_inverse(b.bw); - rational na = mod(inv_b * ne, rational::power_of_two(a.bw)); - a.set_value(m_tmp, na); - return a.set_repair(random_bool(), m_tmp); -#endif + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_bnot(bvval const& e, bvval& a) { From d774f07eb3a2f20e9fb58423aeb66b8b217d0cc9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Feb 2024 14:54:15 -0800 Subject: [PATCH 38/69] add eval field to sls-valuation to track temporary values. --- src/ast/sls/bv_sls.cpp | 44 ++-- src/ast/sls/bv_sls.h | 2 +- src/ast/sls/bv_sls_eval.cpp | 413 +++++++++++++++++----------------- src/ast/sls/bv_sls_eval.h | 53 ++--- src/ast/sls/bv_sls_fixed.cpp | 50 ++-- src/ast/sls/bv_sls_fixed.h | 2 +- src/ast/sls/sls_valuation.cpp | 58 +++-- src/ast/sls/sls_valuation.h | 45 ++-- src/test/sls_test.cpp | 8 +- 9 files changed, 339 insertions(+), 336 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index bdc258462..eb0c3532a 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -52,9 +52,6 @@ namespace bv { m_repair_roots.insert(e->get_id()); } } - for (app* t : m_terms.terms()) - if (t && !eval_is_correct(t)) - m_repair_roots.insert(t->get_id()); } void sls::reinit_eval() { @@ -67,7 +64,7 @@ namespace bv { return m_eval.bval0(e); } else if (bv.is_bv(e)) { - auto& w = m_eval.wval0(e); + auto& w = m_eval.wval(e); if (w.fixed.get(i) || should_keep()) return w.get_bit(i); } @@ -142,17 +139,21 @@ namespace bv { void sls::try_repair_down(app* e) { unsigned n = e->get_num_args(); - if (n > 0) { - unsigned s = m_rand(n); - for (unsigned i = 0; i < n; ++i) { - auto j = (i + s) % n; - if (m_eval.try_repair(e, j)) { - set_repair_down(e->get_arg(j)); - return; - } + if (n == 0) { + m_eval.wval(e).commit_eval(); + m_repair_up.insert(e->get_id()); + } + + unsigned s = m_rand(n); + for (unsigned i = 0; i < n; ++i) { + auto j = (i + s) % n; + if (m_eval.try_repair(e, j)) { + set_repair_down(e->get_arg(j)); + return; } } - m_repair_up.insert(e->get_id()); + + // search a new root / random walk to repair } void sls::try_repair_up(app* e) { @@ -174,8 +175,10 @@ namespace bv { return false; if (m.is_bool(e)) return m_eval.bval0(e) == m_eval.bval1(e); - if (bv.is_bv(e)) - return m_eval.wval0(e).eq(m_eval.wval1(e)); + if (bv.is_bv(e)) { + auto const& v = m_eval.wval(e); + return v.eval == v.bits(); + } UNREACHABLE(); return false; } @@ -187,9 +190,8 @@ namespace bv { if (!eval_is_correct(to_app(e))) { verbose_stream() << "missed evaluation #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; if (bv.is_bv(e)) { - auto const& v0 = m_eval.wval0(e); - auto const& v1 = m_eval.wval1(to_app(e)); - verbose_stream() << v0 << "\n" << v1 << "\n"; + auto const& v = m_eval.wval(e); + verbose_stream() << v << "\n" << v.eval << "\n"; } } if (!is_uninterp_const(e)) @@ -199,7 +201,7 @@ namespace bv { if (m.is_bool(e)) mdl->register_decl(f, m.mk_bool_val(m_eval.bval0(e))); else if (bv.is_bv(e)) { - auto const& v = m_eval.wval0(e); + auto const& v = m_eval.wval(e); rational n = v.get_value(); mdl->register_decl(f, bv.mk_numeral(n, v.bw)); } @@ -219,7 +221,7 @@ namespace bv { if (m_repair_roots.contains(e->get_id())) out << "r "; if (bv.is_bv(e)) - out << m_eval.wval0(e); + out << m_eval.wval(e); else if (m.is_bool(e)) out << (m_eval.bval0(e)?"T":"F"); out << "\n"; @@ -239,7 +241,7 @@ namespace bv { verbose_stream() << (down ? "d #" : "u #") << e->get_id() << ": " << mk_bounded_pp(e, m, 1) << " "; - if (bv.is_bv(e)) verbose_stream() << m_eval.wval0(e) << " " << (m_eval.is_fixed0(e) ? "fixed " : " "); + if (bv.is_bv(e)) verbose_stream() << m_eval.wval(e) << " " << (m_eval.is_fixed0(e) ? "fixed " : " "); if (m.is_bool(e)) verbose_stream() << m_eval.bval0(e) << " "; verbose_stream() << "\n"); } diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index d92f991db..cc93175fb 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -99,7 +99,7 @@ namespace bv { /** * Retrieve valuation */ - sls_valuation const& wval(expr* e) const { return m_eval.wval0(e); } + sls_valuation const& wval(expr* e) const { return m_eval.wval(e); } model_ref get_model(); diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 9d0246d49..3dca890a0 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -37,7 +37,7 @@ namespace bv { init_eval_bv(a); else if (is_uninterp(e)) { if (bv.is_bv(e)) { - auto& v = wval0(e); + auto& v = wval(e); for (unsigned i = 0; i < v.bw; ++i) m_tmp.set(i, eval(e, i)); v.set(m_tmp); @@ -80,12 +80,10 @@ namespace bv { bool sls_eval::add_bit_vector(expr* e) { auto bw = bv.get_bv_size(e); - m_values0.reserve(e->get_id() + 1); - if (m_values0.get(e->get_id())) + m_values.reserve(e->get_id() + 1); + if (m_values.get(e->get_id())) return false; - m_values1.reserve(e->get_id() + 1); - m_values0.set(e->get_id(), alloc_valuation(bw)); - m_values1.set(e->get_id(), alloc(sls_pre_valuation, bw)); + m_values.set(e->get_id(), alloc_valuation(bw)); return true; } @@ -115,9 +113,9 @@ namespace bv { m_eval.setx(id, bval1(e), false); else if (m.is_ite(e)) { SASSERT(bv.is_bv(e->get_arg(1))); - auto& val = wval0(e); - auto& val_th = wval0(e->get_arg(1)); - auto& val_el = wval0(e->get_arg(2)); + auto& val = wval(e); + auto& val_th = wval(e->get_arg(1)); + auto& val_el = wval(e->get_arg(2)); if (bval0(e->get_arg(0))) val.set(val_th.bits()); else @@ -129,10 +127,8 @@ namespace bv { } void sls_eval::init_eval_bv(app* e) { - if (bv.is_bv(e)) { - auto& v = wval0(e); - v.set(wval1(e).bits()); - } + if (bv.is_bv(e)) + eval(e).commit_eval(); else if (m.is_bool(e)) m_eval.setx(e->get_id(), bval1_bv(e), false); } @@ -174,8 +170,8 @@ namespace bv { if (m.is_bool(a)) return bval0(a) == bval0(b); else if (bv.is_bv(a)) { - auto const& va = wval0(a); - auto const& vb = wval0(b); + auto const& va = wval(a); + auto const& vb = wval(b); return va.eq(vb); } return m.are_equal(a, b); @@ -221,15 +217,15 @@ namespace bv { SASSERT(e->get_family_id() == bv.get_fid()); auto ucompare = [&](std::function const& f) { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); return f(mpn.compare(a.bits().data(), a.nw, b.bits().data(), b.nw)); }; // x x + 2^{bw-1} const& f) { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); add_p2_1(a, m_tmp); add_p2_1(b, m_tmp2); return f(mpn.compare(m_tmp.data(), a.nw, m_tmp2.data(), b.nw)); @@ -237,8 +233,8 @@ namespace bv { auto umul_overflow = [&]() { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); return a.set_mul(m_tmp2, a.bits(), b.bits()); }; @@ -263,7 +259,7 @@ namespace bv { expr* child; unsigned idx; VERIFY(bv.is_bit2bool(e, child, idx)); - auto& a = wval0(child); + auto& a = wval(child); return a.get_bit(idx); } case OP_BUMUL_NO_OVFL: @@ -272,8 +268,8 @@ namespace bv { return umul_overflow(); case OP_BUADD_OVFL: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); return a.set_add(m_tmp, a.bits(), b.bits()); } case OP_BNEG_OVFL: @@ -300,18 +296,18 @@ namespace bv { return bval0(e); } - sls_valuation& sls_eval::wval1(app* e) const { - auto& val = *m_values1[e->get_id()]; - wval1(e, val); + sls_valuation& sls_eval::eval(app* e) const { + auto& val = *m_values[e->get_id()]; + eval(e, val); return val; } - void sls_eval::wval1(app* e, sls_pre_valuation& val) const { + void sls_eval::eval(app* e, sls_valuation& val) const { SASSERT(bv.is_bv(e)); if (m.is_ite(e)) { SASSERT(bv.is_bv(e->get_arg(1))); - auto& val_th = wval0(e->get_arg(1)); - auto& val_el = wval0(e->get_arg(2)); + auto& val_th = wval(e->get_arg(1)); + auto& val_el = wval(e->get_arg(2)); if (bval0(e->get_arg(0))) val.set(val_th.bits()); else @@ -319,7 +315,7 @@ namespace bv { return; } if (e->get_family_id() == null_family_id) { - val.set(wval0(e).bits()); + val.set(wval(e).bits()); return; } auto set_sdiv = [&]() { @@ -331,8 +327,8 @@ namespace bv { // x < 0, y > 0 -> -d // x > 0, y > 0 -> d // x < 0, y < 0 -> d - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); bool sign_a = a.sign(); bool sign_b = b.sign(); if (b.is_zero()) { @@ -358,13 +354,13 @@ namespace bv { if (sign_a == sign_b) val.set(m_tmp3); else - val.set_sub(val.bits(), m_zero, m_tmp3); + val.set_sub(val.eval, m_zero, m_tmp3); } }; auto mk_rotate_left = [&](unsigned n) { - auto& a = wval0(e->get_arg(0)); - VERIFY(try_repair_rotate_left(a, val, a.bw - n)); + auto& a = wval(e->get_arg(0)); + VERIFY(try_repair_rotate_left(a.bits(), val, a.bw - n)); }; SASSERT(e->get_family_id() == bv.get_fid()); @@ -378,98 +374,98 @@ namespace bv { } case OP_BAND: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits()[i] = a.bits()[i] & b.bits()[i]; + val.eval[i] = a.bits()[i] & b.bits()[i]; break; } case OP_BOR: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits()[i] = a.bits()[i] | b.bits()[i]; + val.eval[i] = a.bits()[i] | b.bits()[i]; break; } case OP_BXOR: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits()[i] = a.bits()[i] ^ b.bits()[i]; + val.eval[i] = a.bits()[i] ^ b.bits()[i]; break; } case OP_BNAND: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) - val.bits()[i] = ~(a.bits()[i] & b.bits()[i]); + val.eval[i] = ~(a.bits()[i] & b.bits()[i]); break; } case OP_BADD: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); - val.set_add(val.bits(), a.bits(), b.bits()); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); + val.set_add(val.eval, a.bits(), b.bits()); break; } case OP_BSUB: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); - val.set_sub(val.bits(), a.bits(), b.bits()); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); + val.set_sub(val.eval, a.bits(), b.bits()); break; } case OP_BMUL: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); val.set_mul(m_tmp2, a.bits(), b.bits()); val.set(m_tmp2); break; } case OP_CONCAT: { SASSERT(e->get_num_args() == 2); - auto const& a = wval0(e->get_arg(0)); - auto const& b = wval0(e->get_arg(1)); + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); for (unsigned i = 0; i < b.bw; ++i) - val.set_bit(i, b.get_bit(i)); + val.eval.set(i, b.get_bit(i)); for (unsigned i = 0; i < a.bw; ++i) - val.set_bit(i + b.bw, a.get_bit(i)); + val.eval.set(i + b.bw, a.get_bit(i)); break; } case OP_EXTRACT: { expr* child; unsigned lo, hi; VERIFY(bv.is_extract(e, lo, hi, child)); - auto const& a = wval0(child); + auto const& a = wval(child); SASSERT(lo <= hi && hi + 1 <= a.bw && hi - lo + 1 == val.bw); for (unsigned i = lo; i <= hi; ++i) - val.set_bit(i - lo, a.get_bit(i)); + val.eval.set(i - lo, a.get_bit(i)); break; } case OP_BNOT: { - auto& a = wval0(e->get_arg(0)); + auto& a = wval(e->get_arg(0)); for (unsigned i = 0; i < a.nw; ++i) - val.bits()[i] = ~a.bits()[i]; + val.eval[i] = ~a.bits()[i]; break; } case OP_BNEG: { - auto& a = wval0(e->get_arg(0)); - val.set_sub(val.bits(), m_zero, a.bits()); + auto& a = wval(e->get_arg(0)); + val.set_sub(val.eval, m_zero, a.bits()); break; } case OP_BIT0: - val.bits().set(0, false); + val.eval.set(0, false); break; case OP_BIT1: - val.bits().set(0, true); + val.eval.set(0, true); break; case OP_BSHL: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); auto sh = b.to_nat(b.bw); if (sh == 0) val.set(a.bits()); @@ -477,13 +473,13 @@ namespace bv { val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.bits().set(i, i >= sh && a.get_bit(i - sh)); + val.eval.set(i, i >= sh && a.get_bit(i - sh)); } break; } case OP_BLSHR: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); auto sh = b.to_nat(b.bw); if (sh == 0) val.set(a.bits()); @@ -491,13 +487,13 @@ namespace bv { val.set_zero(); else { for (unsigned i = 0; i < a.bw; ++i) - val.bits().set(i, i + sh < a.bw && a.get_bit(i + sh)); + val.eval.set(i, i + sh < a.bw && a.get_bit(i + sh)); } break; } case OP_BASHR: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); auto sh = b.to_nat(b.bw); auto sign = a.sign(); if (sh == 0) @@ -519,7 +515,7 @@ namespace bv { break; } case OP_SIGN_EXT: { - auto& a = wval0(e->get_arg(0)); + auto& a = wval(e->get_arg(0)); for (unsigned i = 0; i < a.bw; ++i) m_tmp.set(i, a.get_bit(i)); bool sign = a.sign(); @@ -528,7 +524,7 @@ namespace bv { break; } case OP_ZERO_EXT: { - auto& a = wval0(e->get_arg(0)); + auto& a = wval(e->get_arg(0)); for (unsigned i = 0; i < a.bw; ++i) m_tmp.set(i, a.get_bit(i)); val.set_range(m_tmp, a.bw, val.bw, false); @@ -538,8 +534,8 @@ namespace bv { case OP_BUREM: case OP_BUREM_I: case OP_BUREM0: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); if (b.is_zero()) val.set(a.bits()); @@ -559,8 +555,8 @@ namespace bv { // x < 0, y >= 0 -> y - u // x >= 0, y < 0 -> y + u // x >= 0, y >= 0 -> u - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); if (b.is_zero()) val.set(a.bits()); else { @@ -576,11 +572,11 @@ namespace bv { if (val.is_zero(m_tmp2)) val.set(m_tmp2); else if (a.sign() && b.sign()) - val.set_sub(val.bits(), m_zero, m_tmp2); + val.set_sub(val.eval, m_zero, m_tmp2); else if (a.sign()) - val.set_sub(val.bits(), b.bits(), m_tmp2); + val.set_sub(val.eval, b.bits(), m_tmp2); else if (b.sign()) - val.set_add(val.bits(), b.bits(), m_tmp2); + val.set_add(val.eval, b.bits(), m_tmp2); else val.set(m_tmp2); } @@ -590,8 +586,8 @@ namespace bv { case OP_BUDIV_I: case OP_BUDIV0: { // x div 0 = -1 - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); if (b.is_zero()) val.set(m_minus_one); else { @@ -613,14 +609,14 @@ namespace bv { // b = 0 -> a // else a - sdiv(a, b) * b // - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); if (b.is_zero()) val.set(a.bits()); else { set_sdiv(); val.set_mul(m_tmp, val.bits(), b.bits()); - val.set_sub(val.bits(), a.bits(), m_tmp); + val.set_sub(val.eval, a.bits(), m_tmp); } break; } @@ -635,7 +631,7 @@ namespace bv { break; } case OP_EXT_ROTATE_LEFT: { - auto& b = wval0(e->get_arg(1)); + auto& b = wval(e->get_arg(1)); rational n = b.get_value(); n = mod(n, rational(val.bw)); SASSERT(n.is_unsigned()); @@ -643,7 +639,7 @@ namespace bv { break; } case OP_EXT_ROTATE_RIGHT: { - auto& b = wval0(e->get_arg(1)); + auto& b = wval(e->get_arg(1)); rational n = b.get_value(); n = mod(n, rational(val.bw)); SASSERT(n.is_unsigned()); @@ -682,7 +678,7 @@ namespace bv { UNREACHABLE(); break; } - val.clear_overflow_bits(val.bits()); + val.clear_overflow_bits(val.eval); } digit_t sls_eval::random_bits() { @@ -728,21 +724,21 @@ namespace bv { bool sls_eval::try_repair_bv(app* e, unsigned i) { switch (e->get_decl_kind()) { case OP_BAND: - return try_repair_band(wval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_band(eval_value(e), wval(e, i), wval(e, 1 - i)); case OP_BOR: - return try_repair_bor(wval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_bor(eval_value(e), wval(e, i), wval(e, 1 - i)); case OP_BXOR: - return try_repair_bxor(wval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_bxor(eval_value(e), wval(e, i), wval(e, 1 - i)); case OP_BADD: - return try_repair_add(wval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_add(eval_value(e), wval(e, i), wval(e, 1 - i)); case OP_BSUB: - return try_repair_sub(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_sub(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_BMUL: - return try_repair_mul(wval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_mul(eval_value(e), wval(e, i), wval(e, 1 - i)); case OP_BNOT: - return try_repair_bnot(wval0(e), wval0(e, i)); + return try_repair_bnot(eval_value(e), wval(e, i)); case OP_BNEG: - return try_repair_bneg(wval0(e), wval0(e, i)); + return try_repair_bneg(eval_value(e), wval(e, i)); case OP_BIT0: return false; case OP_BIT1: @@ -753,89 +749,89 @@ namespace bv { return false; case OP_ULEQ: if (i == 0) - return try_repair_ule(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_ule(bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_uge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_uge(bval0(e), wval(e, i), wval(e, 1 - i)); case OP_UGEQ: if (i == 0) - return try_repair_uge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_uge(bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_ule(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_ule(bval0(e), wval(e, i), wval(e, 1 - i)); case OP_UGT: if (i == 0) - return try_repair_ule(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_ule(!bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_uge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_uge(!bval0(e), wval(e, i), wval(e, 1 - i)); case OP_ULT: if (i == 0) - return try_repair_uge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_uge(!bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_ule(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_ule(!bval0(e), wval(e, i), wval(e, 1 - i)); case OP_SLEQ: if (i == 0) - return try_repair_sle(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sle(bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_sge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sge(bval0(e), wval(e, i), wval(e, 1 - i)); case OP_SGEQ: if (i == 0) - return try_repair_sge(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sge(bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_sle(bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sle(bval0(e), wval(e, i), wval(e, 1 - i)); case OP_SGT: if (i == 0) - return try_repair_sle(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sle(!bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_sge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sge(!bval0(e), wval(e, i), wval(e, 1 - i)); case OP_SLT: if (i == 0) - return try_repair_sge(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sge(!bval0(e), wval(e, i), wval(e, 1 - i)); else - return try_repair_sle(!bval0(e), wval0(e, i), wval0(e, 1 - i)); + return try_repair_sle(!bval0(e), wval(e, i), wval(e, 1 - i)); case OP_BASHR: - return try_repair_ashr(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_ashr(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_BLSHR: - return try_repair_lshr(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_lshr(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_BSHL: - return try_repair_shl(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_shl(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_BIT2BOOL: { unsigned idx; expr* arg; VERIFY(bv.is_bit2bool(e, arg, idx)); - return try_repair_bit2bool(wval0(e, 0), idx); + return try_repair_bit2bool(wval(e, 0), idx); } case OP_BUDIV: case OP_BUDIV_I: case OP_BUDIV0: - return try_repair_udiv(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_udiv(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_BUREM: case OP_BUREM_I: case OP_BUREM0: - return try_repair_urem(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_urem(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_ROTATE_LEFT: - return try_repair_rotate_left(wval0(e), wval0(e, 0), e->get_parameter(0).get_int()); + return try_repair_rotate_left(eval_value(e), wval(e, 0), e->get_parameter(0).get_int()); case OP_ROTATE_RIGHT: - return try_repair_rotate_left(wval0(e), wval0(e, 0), wval0(e).bw - e->get_parameter(0).get_int()); + return try_repair_rotate_left(eval_value(e), wval(e, 0), wval(e).bw - e->get_parameter(0).get_int()); case OP_EXT_ROTATE_LEFT: - return try_repair_rotate_left(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_rotate_left(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_EXT_ROTATE_RIGHT: - return try_repair_rotate_right(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_rotate_right(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_ZERO_EXT: - return try_repair_zero_ext(wval0(e), wval0(e, 0)); + return try_repair_zero_ext(eval_value(e), wval(e, 0)); case OP_SIGN_EXT: - return try_repair_sign_ext(wval0(e), wval0(e, 0)); + return try_repair_sign_ext(eval_value(e), wval(e, 0)); case OP_CONCAT: - return try_repair_concat(wval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_concat(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_EXTRACT: { unsigned hi, lo; expr* arg; VERIFY(bv.is_extract(e, lo, hi, arg)); - return try_repair_extract(wval0(e), wval0(arg), lo); + return try_repair_extract(eval_value(e), wval(arg), lo); } case OP_BUMUL_NO_OVFL: - return try_repair_umul_ovfl(!bval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_umul_ovfl(!bval0(e), wval(e, 0), wval(e, 1), i); case OP_BUMUL_OVFL: - return try_repair_umul_ovfl(bval0(e), wval0(e, 0), wval0(e, 1), i); + return try_repair_umul_ovfl(bval0(e), wval(e, 0), wval(e, 1), i); case OP_BUADD_OVFL: case OP_BCOMP: case OP_BNAND: @@ -891,8 +887,8 @@ namespace bv { return true; } else if (bv.is_bv(child)) { - auto & a = wval0(e->get_arg(i)); - auto & b = wval0(e->get_arg(1 - i)); + auto & a = wval(e->get_arg(i)); + auto & b = wval(e->get_arg(1 - i)); if (is_true) return a.try_set(b.bits()); else { @@ -938,7 +934,7 @@ namespace bv { return true; } if (bv.is_bv(e)) - return wval0(child).try_set(wval0(e).bits()); + return wval(child).try_set(wval(e).bits()); return false; } @@ -964,9 +960,9 @@ namespace bv { // e[i] = 0 & b[i] = 0 -> a[i] = random // a := e[i] | (~b[i] & a[i]) - bool sls_eval::try_repair_band(bvval const& e, bvval& a, bvval const& b) { - for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = (e.bits()[i] & ~a.fixed[i]) | (~b.bits()[i] & ~a.fixed[i] & random_bits()); + bool sls_eval::try_repair_band(bvect const& e, bvval& a, bvval const& b) { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = (e[i] & ~a.fixed[i]) | (~b.bits()[i] & ~a.fixed[i] & random_bits()); return a.set_repair(random_bool(), m_tmp); } @@ -975,15 +971,15 @@ namespace bv { // set a[i] to 1 where b[i] = 0, e[i] = 1 // set a[i] to 0 where e[i] = 0, a[i] = 1 // - bool sls_eval::try_repair_bor(bvval const& e, bvval& a, bvval const& b) { - for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = e.bits()[i] & (~b.bits()[i] | random_bits()); + bool sls_eval::try_repair_bor(bvect const& e, bvval& a, bvval const& b) { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = e[i] & (~b.bits()[i] | random_bits()); return a.set_repair(random_bool(), m_tmp); } - bool sls_eval::try_repair_bxor(bvval const& e, bvval& a, bvval const& b) { - for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = e.bits()[i] ^ b.bits()[i]; + bool sls_eval::try_repair_bxor(bvect const& e, bvval& a, bvval const& b) { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = e[i] ^ b.bits()[i]; a.clear_overflow_bits(m_tmp); return a.set_repair(random_bool(), m_tmp); } @@ -993,21 +989,21 @@ namespace bv { // first try to set a := e - b // If this fails, set a to a random value // - bool sls_eval::try_repair_add(bvval const& e, bvval& a, bvval const& b) { - a.set_sub(m_tmp, e.bits(), b.bits()); + bool sls_eval::try_repair_add(bvect const& e, bvval& a, bvval const& b) { + a.set_sub(m_tmp, e, b.bits()); if (a.try_set(m_tmp)) return true; a.get_variant(m_tmp, m_rand); return a.set_repair(random_bool(), m_tmp); } - bool sls_eval::try_repair_sub(bvval const& e, bvval& a, bvval & b, unsigned i) { + bool sls_eval::try_repair_sub(bvect const& e, bvval& a, bvval & b, unsigned i) { if (i == 0) // e = a - b -> a := e + b - a.set_add(m_tmp, e.bits(), b.bits()); + a.set_add(m_tmp, e, b.bits()); else // b := a - e - b.set_sub(m_tmp, a.bits(), e.bits()); + b.set_sub(m_tmp, a.bits(), e); if (a.try_set(m_tmp)) return true; // fall back to a random value @@ -1019,13 +1015,13 @@ namespace bv { * e = a*b, then a = e * b^-1 * 8*e = a*(2b), then a = 4e*b^-1 */ - bool sls_eval::try_repair_mul(bvval const& e, bvval& a, bvval const& b) { - unsigned parity_e = e.parity(e.bits()); + bool sls_eval::try_repair_mul(bvect const& e, bvval& a, bvval const& b) { + unsigned parity_e = b.parity(e); unsigned parity_b = b.parity(b.bits()); - if (e.is_zero()) { + if (b.is_zero(e)) { a.get_variant(m_tmp, m_rand); - for (unsigned i = 0; i < e.bw - parity_b; ++i) + for (unsigned i = 0; i < b.bw - parity_b; ++i) m_tmp.set(i, false); return a.set_repair(random_bool(), m_tmp); } @@ -1046,7 +1042,7 @@ namespace bv { b.get(y); if (parity_b > 0) { b.shift_right(y, parity_b); - for (unsigned i = parity_b; i < e.bw; ++i) + for (unsigned i = parity_b; i < b.bw; ++i) y.set(i, m_rand() % 2 == 0); } @@ -1092,22 +1088,22 @@ namespace bv { a.set_mul(m_tmp, tb, y); SASSERT(a.is_one(m_tmp)); #endif - e.get(m_tmp2); + b.get(m_tmp2); if (parity_e > 0 && parity_b > 0) b.shift_right(m_tmp2, std::min(parity_b, parity_e)); a.set_mul(m_tmp, tb, m_tmp2); return a.set_repair(random_bool(), m_tmp); } - bool sls_eval::try_repair_bnot(bvval const& e, bvval& a) { - for (unsigned i = 0; i < e.nw; ++i) - m_tmp[i] = ~e.bits()[i]; + bool sls_eval::try_repair_bnot(bvect const& e, bvval& a) { + for (unsigned i = 0; i < a.nw; ++i) + m_tmp[i] = ~e[i]; a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } - bool sls_eval::try_repair_bneg(bvval const& e, bvval& a) { - e.set_sub(m_tmp, m_zero, e.bits()); + bool sls_eval::try_repair_bneg(bvect const& e, bvval& a) { + a.set_sub(m_tmp, m_zero, e); return a.try_set(m_tmp); } @@ -1261,11 +1257,11 @@ namespace bv { return a.try_set_bit(idx, !a.get_bit(idx)); } - bool sls_eval::try_repair_shl(bvval const& e, bvval& a, bvval& b, unsigned i) { + bool sls_eval::try_repair_shl(bvect const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { unsigned sh = b.to_nat(b.bw); if (sh == 0) - return a.try_set(e.bits()); + return a.try_set(e); else if (sh >= b.bw) return false; else { @@ -1275,9 +1271,9 @@ namespace bv { // a[bw - sh - 1: 0] = e[bw - 1: sh] // a[bw - 1: bw - sh] = unchanged // - for (unsigned i = 0; i < e.bw - sh; ++i) - m_tmp.set(i, e.get_bit(sh + i)); - for (unsigned i = e.bw - sh; i < e.bw; ++i) + for (unsigned i = 0; i < a.bw - sh; ++i) + m_tmp.set(i, e.get(sh + i)); + for (unsigned i = a.bw - sh; i < a.bw; ++i) m_tmp.set(i, a.get_bit(i)); return a.try_set(m_tmp); } @@ -1292,13 +1288,13 @@ namespace bv { return false; } - bool sls_eval::try_repair_ashr(bvval const& e, bvval & a, bvval& b, unsigned i) { + bool sls_eval::try_repair_ashr(bvect const& e, bvval & a, bvval& b, unsigned i) { if (i == 0) { unsigned sh = b.to_nat(b.bw); if (sh == 0) - return a.try_set(e.bits()); + return a.try_set(e); else if (sh >= b.bw) { - if (e.get_bit(e.bw - 1)) + if (e.get(a.bw - 1)) return a.try_set_bit(a.bw - 1, true); else return a.try_set_bit(a.bw - 1, false); @@ -1309,7 +1305,7 @@ namespace bv { // a[sh-1:0] = a[sh-1:0] // ignore sign for (unsigned i = sh; i < a.bw; ++i) - m_tmp.set(i, e.get_bit(i - sh)); + m_tmp.set(i, e.get(i - sh)); for (unsigned i = 0; i < sh; ++i) m_tmp.set(i, a.get_bit(i)); a.clear_overflow_bits(m_tmp); @@ -1325,7 +1321,7 @@ namespace bv { } } - bool sls_eval::try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i) { + bool sls_eval::try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i) { return try_repair_ashr(e, a, b, i); } @@ -1334,29 +1330,28 @@ namespace bv { // b = 0 => e = -1 // nothing to repair on a // e != -1 => max(a) >=u e - bool sls_eval::try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i) { + bool sls_eval::try_repair_udiv(bvect const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { - if (e.is_zero() && a.is_ones(a.fixed) && a.is_ones()) + if (a.is_zero(e) && a.is_ones(a.fixed) && a.is_ones()) return false; if (b.is_zero()) return false; - if (!e.is_ones()) { + if (!a.is_ones(e)) { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = ~a.fixed[i] | a.bits()[i]; a.clear_overflow_bits(m_tmp); - if (e.bits() > m_tmp) + if (e > m_tmp) return false; } // e = 1 => a := b - if (e.is_one()) { + if (a.is_one(e)) { a.set(m_tmp, b.bits()); return a.set_repair(false, m_tmp); } // b * e + r = a - b.get_variant(m_tmp, m_rand); - while (mul_overflow_on_fixed(e, m_tmp)) { - auto i = b.msb(m_tmp); - m_tmp.set(i, false); + if (mul_overflow_on_fixed(b, e)) { + a.get_variant(m_tmp, m_rand); + return a.set_repair(random_bool(), m_tmp); } for (unsigned i = 0; i < a.nw; ++i) @@ -1369,13 +1364,13 @@ namespace bv { return a.set_repair(true, m_tmp3); } else { - if (e.is_one() && a.is_zero()) { + if (a.is_one(e) && a.is_zero()) { for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = random_bits(); a.clear_overflow_bits(m_tmp); return b.set_repair(true, m_tmp); } - if (e.is_one()) { + if (a.is_one(e)) { a.set(m_tmp, a.bits()); return b.set_repair(true, m_tmp); } @@ -1390,7 +1385,7 @@ namespace bv { while (a.bits() < m_tmp) m_tmp.set(a.msb(m_tmp), false); a.set_sub(m_tmp2, a.bits(), m_tmp); - set_div(m_tmp2, e.bits(), a.bw, m_tmp3, m_tmp4); + set_div(m_tmp2, e, a.bw, m_tmp3, m_tmp4); return b.set_repair(random_bool(), m_tmp4); } } @@ -1405,11 +1400,11 @@ namespace bv { // (s != t => exists y . (mcb(x, y) and y >u t and (s - t) mod y = 0) - bool sls_eval::try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i) { + bool sls_eval::try_repair_urem(bvect const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { if (b.is_zero()) { - a.set(m_tmp, e.bits()); + a.set(m_tmp, e); return a.set_repair(random_bool(), m_tmp); } // a urem b = e: b*y + e = a @@ -1427,12 +1422,11 @@ namespace bv { } while (true) { a.set_mul(m_tmp2, m_tmp, b.bits()); - if (!add_overflow_on_fixed(e, m_tmp2)) + if (!a.set_add(m_tmp3, m_tmp2, e)) break; auto i = b.msb(m_tmp); m_tmp.set(i, false); } - a.set_add(m_tmp3, m_tmp2, e.bits()); return a.set_repair(random_bool(), m_tmp3); } else { @@ -1445,7 +1439,7 @@ namespace bv { // lower y as long as y*b overflows with fixed bits in b for (unsigned i = 0; i < a.nw; ++i) m_tmp[i] = random_bits(); - a.set_sub(m_tmp2, a.bits(), e.bits()); + a.set_sub(m_tmp2, a.bits(), e); set_div(m_tmp2, m_tmp, a.bw, m_tmp3, m_tmp4); a.clear_overflow_bits(m_tmp3); return b.set_repair(random_bool(), m_tmp3); @@ -1466,17 +1460,17 @@ namespace bv { return a.set_mul(m_tmp4, m_tmp3, t); } - bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const { + bool sls_eval::try_repair_rotate_left(bvect const& e, bvval& a, unsigned n) const { // a := rotate_right(e, n) n = (a.bw - n) % a.bw; for (unsigned i = a.bw - n; i < a.bw; ++i) - m_tmp.set(i + n - a.bw, e.get_bit(i)); + m_tmp.set(i + n - a.bw, e.get(i)); for (unsigned i = 0; i < a.bw - n; ++i) - m_tmp.set(i + n, e.get_bit(i)); + m_tmp.set(i + n, e.get(i)); return a.set_repair(true, m_tmp); } - bool sls_eval::try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i) { + bool sls_eval::try_repair_rotate_left(bvect const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { rational n = b.get_value(); n = mod(n, rational(b.bw)); @@ -1490,7 +1484,7 @@ namespace bv { } } - bool sls_eval::try_repair_rotate_right(bvval const& e, bvval& a, bvval& b, unsigned i) { + bool sls_eval::try_repair_rotate_right(bvect const& e, bvval& a, bvval& b, unsigned i) { if (i == 0) { rational n = b.get_value(); n = mod(b.bw - n, rational(b.bw)); @@ -1533,11 +1527,13 @@ namespace bv { // prefix of e must be 1s or 0 and match bit position of last bit in a. // set a to suffix of e, matching signs. // - bool sls_eval::try_repair_sign_ext(bvval const& e, bvval& a) { + bool sls_eval::try_repair_sign_ext(bvect const& e, bvval& a) { for (unsigned i = a.bw; i < e.bw; ++i) - if (e.get_bit(i) != e.get_bit(a.bw - 1)) + if (e.get(i) != e.get(a.bw - 1)) return false; - e.get(m_tmp); + + for (unsigned i = 0; i < e.bw; ++i) + m_tmp[i] = e[i]; a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } @@ -1545,25 +1541,27 @@ namespace bv { // // prefix of e must be 0s. // - bool sls_eval::try_repair_zero_ext(bvval const& e, bvval& a) { + bool sls_eval::try_repair_zero_ext(bvect const& e, bvval& a) { for (unsigned i = a.bw; i < e.bw; ++i) - if (e.get_bit(i)) + if (e.get(i)) return false; - e.get(m_tmp); + + for (unsigned i = 0; i < e.bw; ++i) + m_tmp[i] = e[i]; a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } - bool sls_eval::try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned idx) { + bool sls_eval::try_repair_concat(bvect const& e, bvval& a, bvval& b, unsigned idx) { if (idx == 0) { for (unsigned i = 0; i < a.bw; ++i) - m_tmp.set(i, e.get_bit(i + b.bw)); + m_tmp.set(i, e.get(i + b.bw)); a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } else { for (unsigned i = 0; i < b.bw; ++i) - m_tmp.set(i, e.get_bit(i)); + m_tmp.set(i, e.get(i)); b.clear_overflow_bits(m_tmp); return b.try_set(m_tmp); } @@ -1574,7 +1572,7 @@ namespace bv { // for the randomized assignment, // set a outside of [hi:lo] to random values with preference to 0 or 1 bits // - bool sls_eval::try_repair_extract(bvval const& e, bvval& a, unsigned lo) { + bool sls_eval::try_repair_extract(bvect const& e, bvval& a, unsigned lo) { if (m_rand() % m_config.m_prob_randomize_extract <= 100) { a.get_variant(m_tmp, m_rand); if (0 == (m_rand() % 2)) { @@ -1591,7 +1589,7 @@ namespace bv { else a.get(m_tmp); for (unsigned i = 0; i < e.bw; ++i) - m_tmp.set(i + lo, e.get_bit(i)); + m_tmp.set(i + lo, e.get(i)); return a.try_set(m_tmp); } @@ -1625,8 +1623,11 @@ namespace bv { m_eval[e->get_id()] = b; return true; } - if (bv.is_bv(e)) - return wval0(e).try_set(wval1(to_app(e)).bits()); + if (bv.is_bv(e)) { + auto& v = eval(to_app(e)); + v.commit_eval(); + return true; + } return false; } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 7798562d5..0c6e59c44 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -42,8 +42,7 @@ namespace bv { - scoped_ptr_vector m_values0; // expr-id -> bv valuation - scoped_ptr_vector m_values1; // expr-id -> bv valuation + scoped_ptr_vector m_values; // expr-id -> bv valuation bool_vector m_eval; // expr-id -> boolean valuation bool_vector m_fixed; // expr-id -> is Boolean fixed @@ -77,36 +76,36 @@ namespace bv { bool try_repair_xor(app* e, unsigned i); bool try_repair_ite(app* e, unsigned i); bool try_repair_implies(app* e, unsigned i); - bool try_repair_band(bvval const& e, bvval& a, bvval const& b); - bool try_repair_bor(bvval const& e, bvval& a, bvval const& b); - bool try_repair_add(bvval const& e, bvval& a, bvval const& b); - bool try_repair_sub(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_mul(bvval const& e, bvval& a, bvval const& b); - bool try_repair_bxor(bvval const& e, bvval& a, bvval const& b); - bool try_repair_bnot(bvval const& e, bvval& a); - bool try_repair_bneg(bvval const& e, bvval& a); + bool try_repair_band(bvect const& e, bvval& a, bvval const& b); + bool try_repair_bor(bvect const& e, bvval& a, bvval const& b); + bool try_repair_add(bvect const& e, bvval& a, bvval const& b); + bool try_repair_sub(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_mul(bvect const& e, bvval& a, bvval const& b); + bool try_repair_bxor(bvect const& e, bvval& a, bvval const& b); + bool try_repair_bnot(bvect const& e, bvval& a); + bool try_repair_bneg(bvect const& e, bvval& a); bool try_repair_ule(bool e, bvval& a, bvval const& b); bool try_repair_uge(bool e, bvval& a, bvval const& b); bool try_repair_sle(bool e, bvval& a, bvval const& b); bool try_repair_sge(bool e, bvval& a, bvval const& b); bool try_repair_sge(bvval& a, bvect const& b, bvect const& p2); bool try_repair_sle(bvval& a, bvect const& b, bvect const& p2); - bool try_repair_shl(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_ashr(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_lshr(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_shl(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_ashr(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_lshr(bvect const& e, bvval& a, bvval& b, unsigned i); bool try_repair_bit2bool(bvval& a, unsigned idx); - bool try_repair_udiv(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_urem(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_rotate_left(bvval const& e, bvval& a, unsigned n) const; - bool try_repair_rotate_left(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_rotate_right(bvval const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_udiv(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_urem(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_rotate_left(bvect const& e, bvval& a, unsigned n) const; + bool try_repair_rotate_left(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_rotate_right(bvect const& e, bvval& a, bvval& b, unsigned i); bool try_repair_ule(bool e, bvval& a, bvect const& t); bool try_repair_uge(bool e, bvval& a, bvect const& t); bool try_repair_umul_ovfl(bool e, bvval& a, bvval& b, unsigned i); - bool try_repair_zero_ext(bvval const& e, bvval& a); - bool try_repair_sign_ext(bvval const& e, bvval& a); - bool try_repair_concat(bvval const& e, bvval& a, bvval& b, unsigned i); - bool try_repair_extract(bvval const& e, bvval& a, unsigned lo); + bool try_repair_zero_ext(bvect const& e, bvval& a); + bool try_repair_sign_ext(bvect const& e, bvval& a); + bool try_repair_concat(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_extract(bvect const& e, bvval& a, unsigned lo); void add_p2_1(bvval const& a, bvect& t) const; bool add_overflow_on_fixed(bvval const& a, bvect const& t); @@ -117,9 +116,11 @@ namespace bv { digit_t random_bits(); bool random_bool() { return m_rand() % 2 == 0; } - sls_valuation& wval0(app* e, unsigned i) { return wval0(e->get_arg(i)); } + sls_valuation& wval(app* e, unsigned i) { return wval(e->get_arg(i)); } - void wval1(app* e, sls_pre_valuation& val) const; + void eval(app* e, sls_valuation& val) const; + + bvect const& eval_value(app* e) const { return wval(e).eval; } public: sls_eval(ast_manager& m); @@ -138,7 +139,7 @@ namespace bv { bool bval0(expr* e) const { return m_eval[e->get_id()]; } - sls_valuation& wval0(expr* e) const { return *m_values0[e->get_id()]; } + sls_valuation& wval(expr* e) const { return *m_values[e->get_id()]; } bool is_fixed0(expr* e) const { return m_fixed[e->get_id()]; } @@ -148,7 +149,7 @@ namespace bv { bool bval1(app* e) const; bool can_eval1(app* e) const; - sls_valuation& wval1(app* e) const; + sls_valuation& eval(app* e) const; /** * Override evaluaton. diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 90899e802..4f49f2648 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -109,7 +109,7 @@ namespace bv { init_range(s, -a, nullptr, rational(0), false); } else if (bv.is_bit2bool(e, s, idx)) { - auto& val = wval0(s); + auto& val = wval(s); val.try_set_bit(idx, !sign); val.fixed.set(idx, true); val.init_fixed(); @@ -132,7 +132,7 @@ namespace bv { // a <= y + b if (a == 0) return; - auto& v = wval0(y); + auto& v = wval(y); if (!sign) v.add_range(a - b, -b); else @@ -142,7 +142,7 @@ namespace bv { if (mod(b + 1, rational::power_of_two(bv.get_bv_size(x))) == 0) return; - auto& v = wval0(x); + auto& v = wval(x); if (!sign) v.add_range(-a, b - a + 1); else @@ -151,7 +151,7 @@ namespace bv { else if (x == y) { if (a == b) return; - auto& v = wval0(x); + auto& v = wval(x); if (!sign) v.add_range(-a, -b); else @@ -174,15 +174,15 @@ namespace bv { x = nullptr; } - sls_valuation& sls_fixed::wval0(expr* e) { - return ev.wval0(e); + sls_valuation& sls_fixed::wval(expr* e) { + return ev.wval(e); } void sls_fixed::init_fixed_basic(app* e) { if (bv.is_bv(e) && m.is_ite(e)) { - auto& val = wval0(e); - auto& val_th = wval0(e->get_arg(1)); - auto& val_el = wval0(e->get_arg(2)); + auto& val = wval(e); + auto& val_th = wval(e->get_arg(1)); + auto& val_el = wval(e->get_arg(2)); for (unsigned i = 0; i < val.nw; ++i) val.fixed[i] = val_el.fixed[i] & val_th.fixed[i] & ~(val_el.bits(i) ^ val_th.bits(i)); val.init_fixed(); @@ -219,7 +219,7 @@ namespace bv { void sls_fixed::set_fixed_bw(app* e) { SASSERT(bv.is_bv(e)); SASSERT(e->get_family_id() == bv.get_fid()); - auto& v = ev.wval0(e); + auto& v = ev.wval(e); if (all_of(*e, [&](expr* arg) { return ev.is_fixed0(arg); })) { for (unsigned i = 0; i < v.bw; ++i) v.fixed.set(i, true); @@ -228,37 +228,37 @@ namespace bv { } switch (e->get_decl_kind()) { case OP_BAND: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); // (a.fixed & b.fixed) | (a.fixed & ~a.bits) | (b.fixed & ~b.bits) for (unsigned i = 0; i < a.nw; ++i) v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & ~a.bits(i)) | (b.fixed[i] & ~b.bits(i)); break; } case OP_BOR: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); // (a.fixed & b.fixed) | (a.fixed & a.bits) | (b.fixed & b.bits) for (unsigned i = 0; i < a.nw; ++i) v.fixed[i] = (a.fixed[i] & b.fixed[i]) | (a.fixed[i] & a.bits(i)) | (b.fixed[i] & b.bits(i)); break; } case OP_BXOR: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); for (unsigned i = 0; i < a.nw; ++i) v.fixed[i] = a.fixed[i] & b.fixed[i]; break; } case OP_BNOT: { - auto& a = wval0(e->get_arg(0)); + auto& a = wval(e->get_arg(0)); for (unsigned i = 0; i < a.nw; ++i) v.fixed[i] = a.fixed[i]; break; } case OP_BADD: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); rational r; if (bv.is_numeral(e->get_arg(0), r) && b.has_range()) v.add_range(r + b.lo(), r + b.hi()); @@ -282,8 +282,8 @@ namespace bv { break; } case OP_BMUL: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); unsigned j = 0, k = 0, zj = 0, zk = 0, hzj = 0, hzk = 0; // i'th bit depends on bits j + k = i // if the first j, resp k bits are 0, the bits j + k are 0 @@ -333,8 +333,8 @@ namespace bv { break; } case OP_CONCAT: { - auto& a = wval0(e->get_arg(0)); - auto& b = wval0(e->get_arg(1)); + auto& a = wval(e->get_arg(0)); + auto& b = wval(e->get_arg(1)); for (unsigned i = 0; i < b.bw; ++i) v.fixed.set(i, b.fixed.get(i)); for (unsigned i = 0; i < a.bw; ++i) @@ -345,13 +345,13 @@ namespace bv { expr* child; unsigned lo, hi; VERIFY(bv.is_extract(e, lo, hi, child)); - auto& a = wval0(child); + auto& a = wval(child); for (unsigned i = lo; i <= hi; ++i) v.fixed.set(i - lo, a.fixed.get(i)); break; } case OP_BNEG: { - auto& a = wval0(e->get_arg(0)); + auto& a = wval(e->get_arg(0)); bool pfixed = true; for (unsigned i = 0; i < v.bw; ++i) { if (pfixed && a.fixed.get(i)) diff --git a/src/ast/sls/bv_sls_fixed.h b/src/ast/sls/bv_sls_fixed.h index 2dfedca19..14970c20c 100644 --- a/src/ast/sls/bv_sls_fixed.h +++ b/src/ast/sls/bv_sls_fixed.h @@ -41,7 +41,7 @@ namespace bv { bool is_fixed1_basic(app* e) const; void set_fixed_bw(app* e); - sls_valuation& wval0(expr* e); + sls_valuation& wval(expr* e); public: sls_fixed(sls_eval& ev); diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 33f9c4452..aad26a367 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -56,15 +56,34 @@ namespace bv { return mpn_manager().compare(a.data(), a.nw, b.data(), a.nw) >= 0; } + std::ostream& operator<<(std::ostream& out, bvect const& v) { + out << std::hex; + bool nz = false; + for (unsigned i = v.nw; i-- > 0;) { + auto w = v[i]; + if (i + 1 == v.nw) + w &= v.mask; + if (nz) + out << std::setw(8) << std::setfill('0') << w; + else if (w != 0) + out << w, nz = true; + } + if (!nz) + out << "0"; + out << std::dec; + return out; + } + sls_valuation::sls_valuation(unsigned bw) { set_bw(bw); m_lo.set_bw(bw); m_hi.set_bw(bw); m_bits.set_bw(bw); fixed.set_bw(bw); + eval.set_bw(bw); // have lo, hi bits, fixed point to memory allocated within this of size num_bytes each allocated for (unsigned i = 0; i < nw; ++i) - m_lo[i] = 0, m_hi[i] = 0, m_bits[i] = 0, fixed[i] = 0; + m_lo[i] = 0, m_hi[i] = 0, m_bits[i] = 0, fixed[i] = 0, eval[i] = 0; fixed[nw - 1] = ~mask; } @@ -76,6 +95,16 @@ namespace bv { mask = ~(digit_t)0; } + void sls_valuation::commit_eval() { + DEBUG_CODE( + for (unsigned i = 0; i < nw; ++i) + VERIFY(0 == (fixed[i] & (m_bits[i] ^ eval[i]))); + ); + for (unsigned i = 0; i < nw; ++i) + m_bits[i] = eval[i]; + SASSERT(well_formed()); + } + bool sls_valuation::in_range(bvect const& bits) const { mpn_manager m; auto c = m.compare(m_lo.data(), nw, m_hi.data(), nw); @@ -303,9 +332,7 @@ namespace bv { if (!ok) VERIFY(try_down ? round_up(dst) : round_down(dst)); DEBUG_CODE(SASSERT(0 == (mask & (fixed[nw-1] & (m_bits[nw-1] ^ dst[nw-1])))); for (unsigned i = 0; i + 1 < nw; ++i) SASSERT(0 == (fixed[i] & (m_bits[i] ^ dst[i])));); - if (m_bits == dst) - return false; - set(m_bits, dst); + set(eval, dst); SASSERT(well_formed()); return true; } @@ -452,8 +479,8 @@ namespace bv { } SASSERT(!has_overflow(m_lo)); SASSERT(!has_overflow(m_hi)); - if (!in_range(m_bits)) - set(m_bits, m_lo); + if (!in_range(eval)) + set(eval, m_lo); SASSERT(well_formed()); } @@ -518,7 +545,7 @@ namespace bv { auto set_fixed_bit = [&](unsigned i, bool b) { if (!fixed.get(i)) { fixed.set(i, true); - m_bits.set(i, b); + eval.set(i, b); } }; @@ -575,22 +602,5 @@ namespace bv { return c == 1; } - std::ostream& sls_valuation::print_bits(std::ostream& out, bvect const& v) const { - bool nz = false; - for (unsigned i = nw; i-- > 0;) { - auto w = v[i]; - if (i + 1 == nw) - w &= mask; - if (nz) - out << std::setw(8) << std::setfill('0') << w; - else if (w != 0) - out << w, nz = true; - } - - if (!nz) - out << "0"; - return out; - } - } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 9f199bb6d..ae8bee5f4 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -28,10 +28,11 @@ Author: namespace bv { class bvect : public svector { + public: unsigned bw = 0; unsigned nw = 0; unsigned mask = 0; - public: + bvect() {} bvect(unsigned sz) : svector(sz, (unsigned)0) {} void set_bw(unsigned bw); @@ -54,6 +55,7 @@ namespace bv { friend bool operator>(bvect const& a, bvect const& b); friend bool operator<=(bvect const& a, bvect const& b); friend bool operator>=(bvect const& a, bvect const& b); + friend std::ostream& operator<<(std::ostream& out, bvect const& v); private: @@ -76,6 +78,7 @@ namespace bv { bool operator>=(bvect const& a, bvect const& b); bool operator>(bvect const& a, bvect const& b); inline bool operator!=(bvect const& a, bvect const& b) { return !(a == b); } + std::ostream& operator<<(std::ostream& out, bvect const& v); class sls_valuation { protected: @@ -87,13 +90,12 @@ namespace bv { bool round_up(bvect& dst) const; bool round_down(bvect& dst) const; - std::ostream& print_bits(std::ostream& out, bvect const& bits) const; - public: unsigned bw; // bit-width unsigned nw; // num words bvect fixed; // bit assignment and don't care bit + bvect eval; // current evaluation sls_valuation(unsigned bw); @@ -103,25 +105,28 @@ namespace bv { digit_t bits(unsigned i) const { return m_bits[i]; } bvect const& bits() const { return m_bits; } + void commit_eval(); bool get_bit(unsigned i) const { return m_bits.get(i); } bool try_set_bit(unsigned i, bool b) { SASSERT(in_range(m_bits)); if (fixed.get(i) && get_bit(i) != b) return false; - m_bits.set(i, b); + eval.set(i, b); if (in_range(m_bits)) return true; - m_bits.set(i, !b); + eval.set(i, !b); return false; } void set_value(bvect& bits, rational const& r); rational get_value() const { return get_value(m_bits); } + rational get_eval() const { return get_value(eval); } rational lo() const { return get_value(m_lo); } rational hi() const { return get_value(m_hi); } + void get(bvect& dst) const; void add_range(rational lo, rational hi); bool has_range() const { return m_lo != m_hi; } @@ -209,8 +214,8 @@ namespace bv { void set(bvect const& src) { for (unsigned i = nw; i-- > 0; ) - m_bits[i] = src[i]; - clear_overflow_bits(m_bits); + eval[i] = src[i]; + clear_overflow_bits(eval); } void set_zero(bvect& out) const { @@ -225,7 +230,7 @@ namespace bv { } void set_zero() { - set_zero(m_bits); + set_zero(eval); } void sub1(bvect& out) const { @@ -272,20 +277,11 @@ namespace bv { unsigned to_nat(unsigned max_n); std::ostream& display(std::ostream& out) const { - out << std::hex; - - print_bits(out, m_bits); + out << m_bits; out << " fix:"; - print_bits(out, fixed); - - if (m_lo != m_hi) { - out << " ["; - print_bits(out, m_lo); - out << ", "; - print_bits(out, m_hi); - out << "["; - } - out << std::dec; + out << fixed; + if (m_lo != m_hi) + out << " [" << m_lo << ", " << m_hi << "["; return out; } @@ -295,13 +291,6 @@ namespace bv { }; - class sls_pre_valuation : public sls_valuation { - public: - sls_pre_valuation(unsigned bw) :sls_valuation(bw) {} - bvect& bits() { return m_bits; } - void set_bit(unsigned i, bool v) { m_bits.set(i, v); } - }; - inline std::ostream& operator<<(std::ostream& out, sls_valuation const& v) { return v.display(out); } } diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp index 8d242e67a..44615e72b 100644 --- a/src/test/sls_test.cpp +++ b/src/test/sls_test.cpp @@ -36,7 +36,7 @@ namespace bv { rw(r); if (bv.is_bv(e)) { - auto const& val = ev.wval0(e); + auto const& val = ev.wval(e); rational n1, n2; n1 = val.get_value(); @@ -164,15 +164,15 @@ namespace bv { } } if (bv.is_bv(e1)) { - auto& val1 = ev.wval0(e1); - auto& val2 = ev.wval0(e2); + auto& val1 = ev.wval(e1); + auto& val2 = ev.wval(e2); if (!val1.eq(val2)) { val2.set(val1.bits()); auto rep2 = ev.try_repair(to_app(e2), idx); if (!rep2) { verbose_stream() << "Not repaired " << mk_pp(e2, m) << "\n"; } - auto val3 = ev.wval0(e2); + auto val3 = ev.wval(e2); if (!val3.eq(val1)) { verbose_stream() << "Repaired but not corrected " << mk_pp(e2, m) << "\n"; } From f46c3782d69be9384dab169c0dfcd0786f045aaf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Feb 2024 19:49:37 -0800 Subject: [PATCH 39/69] bugfixes --- src/ast/sls/bv_sls_eval.cpp | 33 +++++++++++++++++++++++++++------ src/ast/sls/bv_sls_eval.h | 3 +++ src/ast/sls/sls_valuation.h | 4 ++++ src/test/sls_test.cpp | 10 +++++++--- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 3dca890a0..43921085d 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -615,7 +615,7 @@ namespace bv { val.set(a.bits()); else { set_sdiv(); - val.set_mul(m_tmp, val.bits(), b.bits()); + val.set_mul(m_tmp, val.eval, b.bits()); val.set_sub(val.eval, a.bits(), m_tmp); } break; @@ -685,7 +685,7 @@ namespace bv { return sls_valuation::random_bits(m_rand); } - bool sls_eval::try_repair(app* e, unsigned i) { + bool sls_eval::try_repair(app* e, unsigned i) { if (is_fixed0(e->get_arg(i))) return false; else if (e->get_family_id() == basic_family_id) @@ -844,6 +844,7 @@ namespace bv { case OP_BSMUL_NO_OVFL: case OP_BSMUL_NO_UDFL: case OP_BSMUL_OVFL: + verbose_stream() << mk_pp(e, m) << "\n"; return false; case OP_BSREM: case OP_BSREM_I: @@ -1042,8 +1043,10 @@ namespace bv { b.get(y); if (parity_b > 0) { b.shift_right(y, parity_b); +#if 0 for (unsigned i = parity_b; i < b.bw; ++i) y.set(i, m_rand() % 2 == 0); +#endif } y[a.nw] = 0; @@ -1127,10 +1130,12 @@ namespace bv { else { auto& b1 = m_nexta; a.set_add(b1, b.bits(), m_one); + b1.set_bw(b.bw); if (p2 == b1) r = false; else r = try_repair_sge(a, b1, p2); + b1.set_bw(0); } p2.set_bw(0); return r; @@ -1148,7 +1153,7 @@ namespace bv { bool r = false; if (e) r = try_repair_sge(a, b.bits(), p2); - else if (b.is_zero()) + else if (b.bits() == p2) r = false; else { auto& b1 = m_nexta; @@ -1201,7 +1206,7 @@ namespace bv { a.set_sub(p2_1, p2, m_one); p2_1.set_bw(a.bw); bool r = false; - if (b < p2) + if (p2 < b) // random b <= x < p2 r = a.set_random_in_range(b, p2_1, m_tmp3, m_rand); else { @@ -1532,7 +1537,7 @@ namespace bv { if (e.get(i) != e.get(a.bw - 1)) return false; - for (unsigned i = 0; i < e.bw; ++i) + for (unsigned i = 0; i < e.nw; ++i) m_tmp[i] = e[i]; a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); @@ -1546,7 +1551,7 @@ namespace bv { if (e.get(i)) return false; - for (unsigned i = 0; i < e.bw; ++i) + for (unsigned i = 0; i < e.nw; ++i) m_tmp[i] = e[i]; a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); @@ -1630,4 +1635,20 @@ namespace bv { } return false; } + + std::ostream& sls_eval::display(std::ostream& out, expr_ref_vector const& es) { + auto& terms = sort_assertions(es); + for (expr* e : terms) { + out << e->get_id() << ": " << mk_bounded_pp(e, m, 1) << " "; + if (is_fixed0(e)) + out << "f "; + if (bv.is_bv(e)) + out << wval(e); + else if (m.is_bool(e)) + out << (bval0(e) ? "T" : "F"); + out << "\n"; + } + terms.reset(); + return out; + } } diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 0c6e59c44..310892f2b 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -169,5 +169,8 @@ namespace bv { * Propagate repair up to parent */ bool repair_up(expr* e); + + + std::ostream& display(std::ostream& out, expr_ref_vector const& es); }; } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index ae8bee5f4..39b70ce07 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -37,6 +37,10 @@ namespace bv { bvect(unsigned sz) : svector(sz, (unsigned)0) {} void set_bw(unsigned bw); + void set(unsigned bit_idx, bool val) { + auto _val = static_cast(0 - static_cast(val)); + get_bit_word(bit_idx) ^= (_val ^ get_bit_word(bit_idx)) & get_pos_mask(bit_idx); + } bool get(unsigned bit_idx) const { return (get_bit_word(bit_idx) & get_pos_mask(bit_idx)) != 0; diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp index 44615e72b..9d0b569a7 100644 --- a/src/test/sls_test.cpp +++ b/src/test/sls_test.cpp @@ -154,11 +154,13 @@ namespace bv { ev.set(e2, val); auto rep1 = ev.try_repair(to_app(e2), idx); if (!rep1) { - verbose_stream() << "Not repaired " << mk_pp(e2, m) << " r: " << r << "\n"; + verbose_stream() << "Not repaired " << mk_pp(e1, m) << " " << mk_pp(e2, m) << " r: " << r << "\n"; } auto val3 = ev.bval0(e2); if (val3 != val) { verbose_stream() << "Repaired but not corrected " << mk_pp(e2, m) << "\n"; + ev.display(std::cout, es); + exit(0); } //SASSERT(rep1); } @@ -171,8 +173,9 @@ namespace bv { auto rep2 = ev.try_repair(to_app(e2), idx); if (!rep2) { verbose_stream() << "Not repaired " << mk_pp(e2, m) << "\n"; - } + } auto val3 = ev.wval(e2); + val3.commit_eval(); if (!val3.eq(val1)) { verbose_stream() << "Repaired but not corrected " << mk_pp(e2, m) << "\n"; } @@ -234,6 +237,7 @@ static void test_repair1() { } void tst_sls_test() { - test_repair1(); test_eval1(); + test_repair1(); + } From 9888d87294eb91ace7dee171fd5ab3bbaefb37fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Feb 2024 07:06:05 -0800 Subject: [PATCH 40/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 30 ++++++++++++++++++++---------- src/ast/sls/bv_sls.h | 1 + src/ast/sls/bv_sls_eval.cpp | 10 +++++++++- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index eb0c3532a..b930eeaae 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -83,16 +83,16 @@ namespace bv { } if (!m_repair_up.empty()) { - unsigned index = m_rand(m_repair_up.size()); + unsigned index = m_repair_up.elem_at(m_rand(m_repair_up.size())); m_repair_up.remove(index); - e = m_terms.term(m_repair_up.elem_at(index)); + e = m_terms.term(index); return { false, e }; } if (!m_repair_roots.empty()) { - unsigned index = m_rand(m_repair_up.size()); - e = m_terms.term(m_repair_up.elem_at(index)); - m_repair_roots.remove(index); + unsigned index = m_repair_roots.elem_at(m_rand(m_repair_roots.size())); + e = m_terms.term(index); + m_repair_root = index; return { true, e }; } @@ -107,8 +107,6 @@ namespace bv { auto [down, e] = next_to_repair(); if (!e) return l_true; - if (eval_is_correct(e)) - continue; trace_repair(down, e); @@ -138,10 +136,23 @@ namespace bv { } void sls::try_repair_down(app* e) { + + if (eval_is_correct(e)) { + m_repair_roots.remove(m_repair_root); + m_repair_root = UINT_MAX; + return; + } + unsigned n = e->get_num_args(); if (n == 0) { - m_eval.wval(e).commit_eval(); - m_repair_up.insert(e->get_id()); + auto& v = m_eval.wval(e); + v.commit_eval(); + verbose_stream() << mk_pp(e, m) << " := " << v << "\n"; + for (auto p : m_terms.parents(e)) + m_repair_up.insert(p->get_id()); + m_repair_roots.remove(m_repair_root); + m_repair_root = UINT_MAX; + return; } unsigned s = m_rand(n); @@ -152,7 +163,6 @@ namespace bv { return; } } - // search a new root / random walk to repair } diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index cc93175fb..9e4e6e741 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -46,6 +46,7 @@ namespace bv { sls_stats m_stats; indexed_uint_set m_repair_up, m_repair_roots; unsigned m_repair_down = UINT_MAX; + unsigned m_repair_root = UINT_MAX; ptr_vector m_todo; random_gen m_rand; config m_config; diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 43921085d..83ccb99f0 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -297,8 +297,9 @@ namespace bv { } sls_valuation& sls_eval::eval(app* e) const { - auto& val = *m_values[e->get_id()]; + auto& val = *m_values[e->get_id()]; eval(e, val); + verbose_stream() << "eval " << mk_pp(e, m) << " := " << val << " " << val.eval << "\n"; return val; } @@ -1020,12 +1021,19 @@ namespace bv { unsigned parity_e = b.parity(e); unsigned parity_b = b.parity(b.bits()); + verbose_stream() << e << " := " << a << " * " << b << "\n"; if (b.is_zero(e)) { a.get_variant(m_tmp, m_rand); for (unsigned i = 0; i < b.bw - parity_b; ++i) m_tmp.set(i, false); return a.set_repair(random_bool(), m_tmp); } + + if (b.is_zero()) { + a.get_variant(m_tmp, m_rand); + return a.set_repair(random_bool(), m_tmp); + } + auto& x = m_tmp; auto& y = m_tmp2; From 5455603910da128969dda0fd533806da758db1e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Feb 2024 08:57:54 -0800 Subject: [PATCH 41/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 19 +++++++++++++++++-- src/ast/sls/bv_sls.h | 1 + src/ast/sls/bv_sls_eval.cpp | 6 +++--- src/ast/sls/sls_valuation.cpp | 12 ++++-------- src/ast/sls/sls_valuation.h | 13 +++++++++++-- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index b930eeaae..50ec5da6b 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -138,6 +138,8 @@ namespace bv { void sls::try_repair_down(app* e) { if (eval_is_correct(e)) { +// if (bv.is_bv(e)) +// verbose_stream() << mk_pp(e, m) << " := " << m_eval.wval(e) << "\n"; m_repair_roots.remove(m_repair_root); m_repair_root = UINT_MAX; return; @@ -147,7 +149,6 @@ namespace bv { if (n == 0) { auto& v = m_eval.wval(e); v.commit_eval(); - verbose_stream() << mk_pp(e, m) << " := " << v << "\n"; for (auto p : m_terms.parents(e)) m_repair_up.insert(p->get_id()); m_repair_roots.remove(m_repair_root); @@ -193,11 +194,25 @@ namespace bv { return false; } + + bool sls::re_eval_is_correct(app* e) { + if (!m_eval.can_eval1(e)) + return false; + if (m.is_bool(e)) + return m_eval.bval0(e) == m_eval.bval1(e); + if (bv.is_bv(e)) { + auto const& v = m_eval.eval(e); + return v.eval == v.bits(); + } + UNREACHABLE(); + return false; + } + model_ref sls::get_model() { model_ref mdl = alloc(model, m); auto& terms = m_eval.sort_assertions(m_terms.assertions()); for (expr* e : terms) { - if (!eval_is_correct(to_app(e))) { + if (!re_eval_is_correct(to_app(e))) { verbose_stream() << "missed evaluation #" << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; if (bv.is_bv(e)) { auto const& v = m_eval.wval(e); diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index 9e4e6e741..177ac5069 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -54,6 +54,7 @@ namespace bv { std::pair next_to_repair(); bool eval_is_correct(app* e); + bool re_eval_is_correct(app* e); void try_repair_down(app* e); void try_repair_up(app* e); void set_repair_down(expr* e) { m_repair_down = e->get_id(); } diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 83ccb99f0..d466466f2 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -299,7 +299,6 @@ namespace bv { sls_valuation& sls_eval::eval(app* e) const { auto& val = *m_values[e->get_id()]; eval(e, val); - verbose_stream() << "eval " << mk_pp(e, m) << " := " << val << " " << val.eval << "\n"; return val; } @@ -1021,7 +1020,6 @@ namespace bv { unsigned parity_e = b.parity(e); unsigned parity_b = b.parity(b.bits()); - verbose_stream() << e << " := " << a << " * " << b << "\n"; if (b.is_zero(e)) { a.get_variant(m_tmp, m_rand); for (unsigned i = 0; i < b.bw - parity_b; ++i) @@ -1092,6 +1090,8 @@ namespace bv { y.set_bw(0); // x*a + y*b = 1 + tb.set_bw(b.bw); + tb.set_bw(0); #if Z3DEBUG b.get(y); if (parity_b > 0) @@ -1099,7 +1099,7 @@ namespace bv { a.set_mul(m_tmp, tb, y); SASSERT(a.is_one(m_tmp)); #endif - b.get(m_tmp2); + e.copy_to(b.nw, m_tmp2); if (parity_e > 0 && parity_b > 0) b.shift_right(m_tmp2, std::min(parity_b, parity_e)); a.set_mul(m_tmp, tb, m_tmp2); diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index aad26a367..a410a0157 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -338,10 +338,8 @@ namespace bv { } void sls_valuation::min_feasible(bvect& out) const { - if (m_lo < m_hi) { - for (unsigned i = 0; i < nw; ++i) - out[i] = m_lo[i]; - } + if (m_lo < m_hi) + m_lo.copy_to(nw, out); else { for (unsigned i = 0; i < nw; ++i) out[i] = fixed[i] & m_bits[i]; @@ -351,8 +349,7 @@ namespace bv { void sls_valuation::max_feasible(bvect& out) const { if (m_lo < m_hi) { - for (unsigned i = 0; i < nw; ++i) - out[i] = m_hi[i]; + m_hi.copy_to(nw, out); sub1(out); } else { @@ -386,8 +383,7 @@ namespace bv { } void sls_valuation::get(bvect& dst) const { - for (unsigned i = 0; i < nw; ++i) - dst[i] = m_bits[i]; + m_bits.copy_to(nw, dst); } digit_t sls_valuation::random_bits(random_gen& rand) { diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 39b70ce07..88d8509d7 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -37,6 +37,12 @@ namespace bv { bvect(unsigned sz) : svector(sz, (unsigned)0) {} void set_bw(unsigned bw); + void copy_to(unsigned nw, bvect & dst) const { + SASSERT(nw <= this->size()); + for (unsigned i = 0; i < nw; ++i) + dst[i] = (*this)[i]; + } + void set(unsigned bit_idx, bool val) { auto _val = static_cast(0 - static_cast(val)); get_bit_word(bit_idx) ^= (_val ^ get_bit_word(bit_idx)) & get_pos_mask(bit_idx); @@ -282,8 +288,11 @@ namespace bv { std::ostream& display(std::ostream& out) const { out << m_bits; - out << " fix:"; - out << fixed; + out << " ev: " << eval; + if (!is_zero(fixed)) { + out << " fix:"; + out << fixed; + } if (m_lo != m_hi) out << " [" << m_lo << ", " << m_hi << "["; return out; From 803f0f0c65d1be10d684d69f8c36b70e73e59d64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Feb 2024 17:22:20 +0000 Subject: [PATCH 42/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls_eval.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index d466466f2..a215fd5c6 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -504,8 +504,7 @@ namespace bv { val.set(m_tmp); } else { - for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = 0; + a.set_zero(m_tmp); for (unsigned i = 0; i < a.bw; ++i) m_tmp.set(i, i + sh < a.bw && a.get_bit(i + sh)); if (sign) @@ -516,8 +515,7 @@ namespace bv { } case OP_SIGN_EXT: { auto& a = wval(e->get_arg(0)); - for (unsigned i = 0; i < a.bw; ++i) - m_tmp.set(i, a.get_bit(i)); + a.get(m_tmp); bool sign = a.sign(); val.set_range(m_tmp, a.bw, val.bw, sign); val.set(m_tmp); @@ -525,8 +523,7 @@ namespace bv { } case OP_ZERO_EXT: { auto& a = wval(e->get_arg(0)); - for (unsigned i = 0; i < a.bw; ++i) - m_tmp.set(i, a.get_bit(i)); + a.get(m_tmp); val.set_range(m_tmp, a.bw, val.bw, false); val.set(m_tmp); break; @@ -1367,9 +1364,7 @@ namespace bv { return a.set_repair(random_bool(), m_tmp); } - for (unsigned i = 0; i < a.nw; ++i) - m_tmp2[i] = random_bits(); - b.clear_overflow_bits(m_tmp2); + b.get_variant(m_tmp2, m_rand); while (b.bits() < m_tmp2) m_tmp2.set(b.msb(m_tmp2), false); while (a.set_add(m_tmp3, m_tmp, m_tmp2)) From dfd5c27fec205f9fd939e6a208dac7ffab73cad4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Feb 2024 17:09:41 -0800 Subject: [PATCH 43/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 41 ++++++++++++++++++++++------------- src/ast/sls/bv_sls.h | 2 +- src/ast/sls/bv_sls_eval.cpp | 7 +++++- src/ast/sls/bv_sls_fixed.cpp | 2 +- src/ast/sls/sls_valuation.cpp | 20 +++++++++++------ src/ast/sls/sls_valuation.h | 2 +- 6 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 50ec5da6b..3902957fc 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -52,6 +52,19 @@ namespace bv { m_repair_roots.insert(e->get_id()); } } + for (auto* t : m_terms.terms()) { + if (t && !re_eval_is_correct(t)) + m_repair_roots.insert(t->get_id()); + } + } + + void sls::init_repair_goal(app* t) { + if (m.is_bool(t)) + m_eval.set(t, m_eval.bval1(t)); + else if (bv.is_bv(t)) { + auto& v = m_eval.wval(t); + v.bits().copy_to(v.nw, v.eval); + } } void sls::reinit_eval() { @@ -89,11 +102,18 @@ namespace bv { return { false, e }; } - if (!m_repair_roots.empty()) { + while (!m_repair_roots.empty()) { unsigned index = m_repair_roots.elem_at(m_rand(m_repair_roots.size())); e = m_terms.term(index); - m_repair_root = index; - return { true, e }; + if (m_terms.is_assertion(e) && !m_eval.bval1(e)) { + SASSERT(m_eval.bval0(e)); + return { true, e }; + } + if (!re_eval_is_correct(e)) { + init_repair_goal(e); + return { true, e }; + } + m_repair_roots.remove(index); } return { false, nullptr }; @@ -103,11 +123,12 @@ namespace bv { // init and init_eval were invoked unsigned n = 0; for (; n++ < m_config.m_max_repairs && m.inc(); ) { - ++m_stats.m_moves; auto [down, e] = next_to_repair(); if (!e) return l_true; + ++m_stats.m_moves; + trace_repair(down, e); if (down) @@ -137,22 +158,12 @@ namespace bv { void sls::try_repair_down(app* e) { - if (eval_is_correct(e)) { -// if (bv.is_bv(e)) -// verbose_stream() << mk_pp(e, m) << " := " << m_eval.wval(e) << "\n"; - m_repair_roots.remove(m_repair_root); - m_repair_root = UINT_MAX; - return; - } - unsigned n = e->get_num_args(); if (n == 0) { auto& v = m_eval.wval(e); - v.commit_eval(); + VERIFY(v.commit_eval()); for (auto p : m_terms.parents(e)) m_repair_up.insert(p->get_id()); - m_repair_roots.remove(m_repair_root); - m_repair_root = UINT_MAX; return; } diff --git a/src/ast/sls/bv_sls.h b/src/ast/sls/bv_sls.h index 177ac5069..bbcd59aea 100644 --- a/src/ast/sls/bv_sls.h +++ b/src/ast/sls/bv_sls.h @@ -46,7 +46,6 @@ namespace bv { sls_stats m_stats; indexed_uint_set m_repair_up, m_repair_roots; unsigned m_repair_down = UINT_MAX; - unsigned m_repair_root = UINT_MAX; ptr_vector m_todo; random_gen m_rand; config m_config; @@ -55,6 +54,7 @@ namespace bv { bool eval_is_correct(app* e); bool re_eval_is_correct(app* e); + void init_repair_goal(app* e); void try_repair_down(app* e); void try_repair_up(app* e); void set_repair_down(expr* e) { m_repair_down = e->get_id(); } diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index a215fd5c6..931364e30 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -1100,7 +1100,7 @@ namespace bv { if (parity_e > 0 && parity_b > 0) b.shift_right(m_tmp2, std::min(parity_b, parity_e)); a.set_mul(m_tmp, tb, m_tmp2); - return a.set_repair(random_bool(), m_tmp); + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_bnot(bvect const& e, bvval& a) { @@ -1633,6 +1633,11 @@ namespace bv { } if (bv.is_bv(e)) { auto& v = eval(to_app(e)); + for (unsigned i = 0; i < v.nw; ++i) + if (0 != (v.fixed[i] & (v.bits()[i] ^ v.eval[i]))) { + v.bits().copy_to(v.nw, v.eval); + return false; + } v.commit_eval(); return true; } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 4f49f2648..609842790 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -25,7 +25,7 @@ namespace bv { {} void sls_fixed::init(expr_ref_vector const& es) { - // init_ranges(es); + init_ranges(es); ev.sort_assertions(es); for (expr* e : ev.m_todo) { if (!is_app(e)) diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index a410a0157..d4bf33353 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -95,14 +95,14 @@ namespace bv { mask = ~(digit_t)0; } - void sls_valuation::commit_eval() { - DEBUG_CODE( - for (unsigned i = 0; i < nw; ++i) - VERIFY(0 == (fixed[i] & (m_bits[i] ^ eval[i]))); - ); + bool sls_valuation::commit_eval() { + for (unsigned i = 0; i < nw; ++i) + if (0 != (fixed[i] & (m_bits[i] ^ eval[i]))) + return false; for (unsigned i = 0; i < nw; ++i) m_bits[i] = eval[i]; SASSERT(well_formed()); + return true; } bool sls_valuation::in_range(bvect const& bits) const { @@ -446,6 +446,9 @@ namespace bv { if (h == l) return; + //verbose_stream() << "[" << l << ", " << h << "[\n"; + //verbose_stream() << *this << "\n"; + SASSERT(is_zero(fixed)); // ranges can only be added before fixed bits are set. if (m_lo == m_hi) { @@ -473,10 +476,13 @@ namespace bv { set_value(m_hi, h); } } + + + SASSERT(!has_overflow(m_lo)); SASSERT(!has_overflow(m_hi)); - if (!in_range(eval)) - set(eval, m_lo); + if (!in_range(m_bits)) + set(m_bits, m_lo); SASSERT(well_formed()); } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 88d8509d7..0cd357d4d 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -115,7 +115,7 @@ namespace bv { digit_t bits(unsigned i) const { return m_bits[i]; } bvect const& bits() const { return m_bits; } - void commit_eval(); + bool commit_eval(); bool get_bit(unsigned i) const { return m_bits.get(i); } bool try_set_bit(unsigned i, bool b) { From 5be8872d6a90e6a4133fab4f25f5d880eff8ee11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Feb 2024 08:54:21 -0800 Subject: [PATCH 44/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 11 +++-- src/ast/sls/bv_sls_eval.cpp | 80 +++++++++++++++++++++--------- src/ast/sls/bv_sls_eval.h | 6 ++- src/ast/sls/bv_sls_fixed.cpp | 6 +-- src/ast/sls/sls_valuation.cpp | 92 ++++++++++++++++------------------- src/ast/sls/sls_valuation.h | 7 ++- 6 files changed, 117 insertions(+), 85 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 3902957fc..5c7c16fb1 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -38,8 +38,10 @@ namespace bv { void sls::init_eval(std::function& eval) { m_eval.init_eval(m_terms.assertions(), eval); - m_eval.init_fixed(m_terms.assertions()); + m_eval.tighten_range(m_terms.assertions()); init_repair(); + display(verbose_stream()); + exit(0); } void sls::init_repair() { @@ -160,8 +162,11 @@ namespace bv { unsigned n = e->get_num_args(); if (n == 0) { - auto& v = m_eval.wval(e); - VERIFY(v.commit_eval()); + if (m.is_bool(e)) + m_eval.set(e, m_eval.bval1(e)); + else + VERIFY(m_eval.wval(e).commit_eval()); + for (auto p : m_terms.parents(e)) m_repair_up.insert(p->get_id()); return; diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 931364e30..36f0ebcb3 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -643,11 +643,21 @@ namespace bv { mk_rotate_left(val.bw - n.get_unsigned()); break; } + case OP_BCOMP: { + auto const& a = wval(e->get_arg(0)); + auto const& b = wval(e->get_arg(1)); + if (a.bits() == b.bits()) + val.set(val.eval, 1); + else + val.set(val.eval, 0); + break; + } case OP_BREDAND: case OP_BREDOR: case OP_BXNOR: case OP_INT2BV: - case OP_BCOMP: + + verbose_stream() << mk_bounded_pp(e, m) << "\n"; NOT_IMPLEMENTED_YET(); break; case OP_BIT2BOOL: @@ -829,8 +839,10 @@ namespace bv { return try_repair_umul_ovfl(!bval0(e), wval(e, 0), wval(e, 1), i); case OP_BUMUL_OVFL: return try_repair_umul_ovfl(bval0(e), wval(e, 0), wval(e, 1), i); + case OP_BCOMP: + return try_repair_comp(eval_value(e), wval(e, 0), wval(e, 1), i); case OP_BUADD_OVFL: - case OP_BCOMP: + case OP_BNAND: case OP_BREDAND: case OP_BREDOR: @@ -887,29 +899,33 @@ namespace bv { else if (bv.is_bv(child)) { auto & a = wval(e->get_arg(i)); auto & b = wval(e->get_arg(1 - i)); - if (is_true) - return a.try_set(b.bits()); - else { - bool try_above = m_rand() % 2 == 0; - if (try_above) { - a.set_add(m_tmp, b.bits(), m_one); - if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) - return true; - } - a.set_sub(m_tmp, b.bits(), m_one); - if (!a.is_zero(m_tmp) && a.set_random_at_most(m_tmp, m_tmp2, m_rand)) - return true; - if (!try_above) { - a.set_add(m_tmp, b.bits(), m_one); - if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) - return true; - } - return false; - } + return try_repair_eq(is_true, a, b); } return false; } + bool sls_eval::try_repair_eq(bool is_true, bvval& a, bvval const& b) { + if (is_true) + return a.try_set(b.bits()); + else { + bool try_above = m_rand() % 2 == 0; + if (try_above) { + a.set_add(m_tmp, b.bits(), m_one); + if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) + return true; + } + a.set_sub(m_tmp, b.bits(), m_one); + if (!a.is_zero(m_tmp) && a.set_random_at_most(m_tmp, m_tmp2, m_rand)) + return true; + if (!try_above) { + a.set_add(m_tmp, b.bits(), m_one); + if (!a.is_zero(m_tmp) && a.set_random_at_least(m_tmp, m_tmp2, m_rand)) + return true; + } + return false; + } + } + bool sls_eval::try_repair_xor(app* e, unsigned i) { bool ev = bval0(e); bool bv = bval0(e->get_arg(1 - i)); @@ -1285,6 +1301,7 @@ namespace bv { m_tmp.set(i, e.get(sh + i)); for (unsigned i = a.bw - sh; i < a.bw; ++i) m_tmp.set(i, a.get_bit(i)); + a.clear_overflow_bits(m_tmp); return a.try_set(m_tmp); } } @@ -1335,6 +1352,12 @@ namespace bv { return try_repair_ashr(e, a, b, i); } + bool sls_eval::try_repair_comp(bvect const& e, bvval& a, bvval& b, unsigned i) { + SASSERT(e[0] == 0 || e[0] == 1); + SASSERT(e.bw == 1); + return try_repair_eq(e[0] == 1, i == 0 ? a : b, i == 0 ? b : a); + } + // e = a udiv b // e = 0 => a != ones // b = 0 => e = -1 // nothing to repair on a @@ -1368,7 +1391,8 @@ namespace bv { while (b.bits() < m_tmp2) m_tmp2.set(b.msb(m_tmp2), false); while (a.set_add(m_tmp3, m_tmp, m_tmp2)) - m_tmp2.set(b.msb(m_tmp2), false); + m_tmp2.set(b.msb(m_tmp2), false); + a.clear_overflow_bits(m_tmp3); return a.set_repair(true, m_tmp3); } else { @@ -1561,18 +1585,21 @@ namespace bv { } bool sls_eval::try_repair_concat(bvect const& e, bvval& a, bvval& b, unsigned idx) { + bool r = false; if (idx == 0) { for (unsigned i = 0; i < a.bw; ++i) m_tmp.set(i, e.get(i + b.bw)); a.clear_overflow_bits(m_tmp); - return a.try_set(m_tmp); + r = a.try_set(m_tmp); } else { for (unsigned i = 0; i < b.bw; ++i) m_tmp.set(i, e.get(i)); b.clear_overflow_bits(m_tmp); - return b.try_set(m_tmp); + r = b.try_set(m_tmp); } + verbose_stream() << e << " := " << a << " " << b << "\n"; + return r; } // @@ -1644,6 +1671,11 @@ namespace bv { return false; } + sls_valuation& sls_eval::wval(expr* e) const { + if (!m_values[e->get_id()]) verbose_stream() << mk_bounded_pp(e, m) << "\n"; + return *m_values[e->get_id()]; + } + std::ostream& sls_eval::display(std::ostream& out, expr_ref_vector const& es) { auto& terms = sort_assertions(es); for (expr* e : terms) { diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 310892f2b..42e67609d 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -106,6 +106,8 @@ namespace bv { bool try_repair_sign_ext(bvect const& e, bvval& a); bool try_repair_concat(bvect const& e, bvval& a, bvval& b, unsigned i); bool try_repair_extract(bvect const& e, bvval& a, unsigned lo); + bool try_repair_comp(bvect const& e, bvval& a, bvval& b, unsigned i); + bool try_repair_eq(bool is_true, bvval& a, bvval const& b); void add_p2_1(bvval const& a, bvect& t) const; bool add_overflow_on_fixed(bvval const& a, bvect const& t); @@ -127,7 +129,7 @@ namespace bv { void init_eval(expr_ref_vector const& es, std::function const& eval); - void init_fixed(expr_ref_vector const& es) { m_fix.init(es); } + void tighten_range(expr_ref_vector const& es) { m_fix.init(es); } ptr_vector& sort_assertions(expr_ref_vector const& es); @@ -139,7 +141,7 @@ namespace bv { bool bval0(expr* e) const { return m_eval[e->get_id()]; } - sls_valuation& wval(expr* e) const { return *m_values[e->get_id()]; } + sls_valuation& wval(expr* e) const; bool is_fixed0(expr* e) const { return m_fixed[e->get_id()]; } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index 609842790..e2bd87922 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -112,7 +112,7 @@ namespace bv { auto& val = wval(s); val.try_set_bit(idx, !sign); val.fixed.set(idx, true); - val.init_fixed(); + val.tighten_range(); } } @@ -185,7 +185,7 @@ namespace bv { auto& val_el = wval(e->get_arg(2)); for (unsigned i = 0; i < val.nw; ++i) val.fixed[i] = val_el.fixed[i] & val_th.fixed[i] & ~(val_el.bits(i) ^ val_th.bits(i)); - val.init_fixed(); + val.tighten_range(); } } @@ -420,6 +420,6 @@ namespace bv { UNREACHABLE(); break; } - v.init_fixed(); + v.tighten_range(); } } diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index d4bf33353..225bf9e1e 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -446,8 +446,8 @@ namespace bv { if (h == l) return; - //verbose_stream() << "[" << l << ", " << h << "[\n"; - //verbose_stream() << *this << "\n"; + verbose_stream() << "[" << l << ", " << h << "[\n"; + verbose_stream() << *this << "\n"; SASSERT(is_zero(fixed)); // ranges can only be added before fixed bits are set. @@ -481,9 +481,10 @@ namespace bv { SASSERT(!has_overflow(m_lo)); SASSERT(!has_overflow(m_hi)); - if (!in_range(m_bits)) + if (!in_range(m_bits)) set(m_bits, m_lo); SASSERT(well_formed()); + verbose_stream() << *this << "\n"; } // @@ -499,7 +500,9 @@ namespace bv { // lo + 1 = hi -> set bits = lo // lo < hi, set most significant bits based on hi // - void sls_valuation::init_fixed() { + void sls_valuation::tighten_range() { + + verbose_stream() << "tighten " << *this << "\n"; if (m_lo == m_hi) return; for (unsigned i = bw; i-- > 0; ) { @@ -518,56 +521,47 @@ namespace bv { } break; } - bvect hi1(nw + 1); - bvect one(nw + 1); - one[0] = 1; - digit_t c; - mpn_manager().sub(m_hi.data(), nw, one.data(), nw, hi1.data(), &c); - clear_overflow_bits(hi1); - for (unsigned i = bw; i-- > 0; ) { - if (!fixed.get(i)) - continue; - if (m_bits.get(i) == hi1.get(i)) - continue; - if (hi1.get(i)) { - hi1.set(i, false); - for (unsigned j = i; j-- > 0; ) - hi1.set(j, !fixed.get(j) || m_bits.get(j)); + + if (!in_range(m_bits)) { + verbose_stream() << "not in range\n"; + bool compatible = true; + for (unsigned i = 0; i < nw && compatible; ++i) + compatible = 0 == (fixed[i] && (m_bits[i] ^ m_lo[i])); + verbose_stream() << (fixed[0] && (m_bits[0] ^ m_lo[0])) << "\n"; + + if (compatible) { + verbose_stream() << "compatible\n"; + set(m_bits, m_lo); } else { - for (unsigned j = bw; j-- > 0; ) - hi1.set(j, fixed.get(j) && m_bits.get(j)); + bvect tmp(m_bits.nw); + tmp.set_bw(bw); + set(tmp, m_lo); + unsigned max_diff = bw; + for (unsigned i = 0; i < bw; ++i) { + if (fixed.get(i) && (m_bits.get(i) ^ m_lo.get(i))) { + tmp.set(i, m_bits.get(i)); + max_diff = i; + } + } + SASSERT(max_diff != bw); + + for (unsigned i = 0; i <= max_diff; ++i) + tmp.set(i, fixed.get(i) && m_bits.get(i)); + + bool found0 = false; + for (unsigned i = max_diff + 1; i < bw; ++i) { + if (found0 || m_lo.get(i) || fixed.get(i)) + tmp.set(i, m_lo.get(i) && fixed.get(i)); + else { + tmp.set(i, true); + found0 = true; + } + } + set(m_bits, tmp); } - mpn_manager().add(hi1.data(), nw, one.data(), nw, m_hi.data(), nw + 1, &c); - clear_overflow_bits(m_hi); - break; } - // set fixed bits based on bounds - auto set_fixed_bit = [&](unsigned i, bool b) { - if (!fixed.get(i)) { - fixed.set(i, true); - eval.set(i, b); - } - }; - - // set most significant bits - if (m_lo < m_hi) { - unsigned i = bw; - for (; i-- > 0 && !m_hi.get(i); ) - set_fixed_bit(i, false); - - if (is_power_of2(m_hi)) - set_fixed_bit(i, false); - } - - // lo + 1 = hi: then bits = lo - mpn_manager().add(m_lo.data(), nw, one.data(), nw, hi1.data(), nw + 1, &c); - clear_overflow_bits(hi1); - if (m_hi == hi1) { - for (unsigned i = 0; i < bw; ++i) - set_fixed_bit(i, m_lo.get(i)); - } SASSERT(well_formed()); } diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index 0cd357d4d..cbe1a35a4 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -140,7 +140,7 @@ namespace bv { void get(bvect& dst) const; void add_range(rational lo, rational hi); bool has_range() const { return m_lo != m_hi; } - void init_fixed(); + void tighten_range(); void clear_overflow_bits(bvect& bits) const { SASSERT(nw > 0); @@ -156,11 +156,10 @@ namespace bv { bool is_zero() const { return is_zero(m_bits); } bool is_zero(bvect const& a) const { - SASSERT(!has_overflow(a)); - for (unsigned i = 0; i < nw; ++i) + for (unsigned i = 0; i < nw - 1; ++i) if (a[i] != 0) return false; - return true; + return (a[nw - 1] & mask) == 0; } bool is_ones() const { return is_ones(m_bits); } From 22616da63bdb2c43d8dd9644ba1fb1f09a8a54fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Feb 2024 16:59:03 -0800 Subject: [PATCH 45/69] updates --- src/ast/sls/bv_sls.cpp | 2 - src/ast/sls/bv_sls_eval.cpp | 18 +++-- src/ast/sls/bv_sls_fixed.cpp | 4 +- src/ast/sls/sls_valuation.cpp | 99 +++++++++++++++--------- src/tactic/core/simplify_tactic.cpp | 9 +++ src/tactic/core/simplify_tactic.h | 2 + src/tactic/dependent_expr_state_tactic.h | 15 ++-- src/tactic/tactic.h | 3 +- src/tactic/tactical.cpp | 4 + 9 files changed, 101 insertions(+), 55 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 5c7c16fb1..108abd891 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -40,8 +40,6 @@ namespace bv { m_eval.init_eval(m_terms.assertions(), eval); m_eval.tighten_range(m_terms.assertions()); init_repair(); - display(verbose_stream()); - exit(0); } void sls::init_repair() { diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 36f0ebcb3..592c92b1c 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -1598,7 +1598,7 @@ namespace bv { b.clear_overflow_bits(m_tmp); r = b.try_set(m_tmp); } - verbose_stream() << e << " := " << a << " " << b << "\n"; + //verbose_stream() << e << " := " << a << " " << b << "\n"; return r; } @@ -1625,7 +1625,12 @@ namespace bv { a.get(m_tmp); for (unsigned i = 0; i < e.bw; ++i) m_tmp.set(i + lo, e.get(i)); - return a.try_set(m_tmp); + if (a.try_set(m_tmp)) + return true; + a.get_variant(m_tmp, m_rand); + bool res = a.set_repair(random_bool(), m_tmp); + // verbose_stream() << "try set " << res << " " << m_tmp[0] << " " << a << "\n"; + return res; } void sls_eval::set_div(bvect const& a, bvect const& b, unsigned bw, @@ -1660,19 +1665,22 @@ namespace bv { } if (bv.is_bv(e)) { auto& v = eval(to_app(e)); + // verbose_stream() << "committing: " << v << "\n"; for (unsigned i = 0; i < v.nw; ++i) if (0 != (v.fixed[i] & (v.bits()[i] ^ v.eval[i]))) { v.bits().copy_to(v.nw, v.eval); return false; } - v.commit_eval(); - return true; + if (v.commit_eval()) + return true; + v.bits().copy_to(v.nw, v.eval); + return false; } return false; } sls_valuation& sls_eval::wval(expr* e) const { - if (!m_values[e->get_id()]) verbose_stream() << mk_bounded_pp(e, m) << "\n"; + // if (!m_values[e->get_id()]) verbose_stream() << mk_bounded_pp(e, m) << "\n"; return *m_values[e->get_id()]; } diff --git a/src/ast/sls/bv_sls_fixed.cpp b/src/ast/sls/bv_sls_fixed.cpp index e2bd87922..91ce8e0e2 100644 --- a/src/ast/sls/bv_sls_fixed.cpp +++ b/src/ast/sls/bv_sls_fixed.cpp @@ -25,7 +25,6 @@ namespace bv { {} void sls_fixed::init(expr_ref_vector const& es) { - init_ranges(es); ev.sort_assertions(es); for (expr* e : ev.m_todo) { if (!is_app(e)) @@ -40,6 +39,7 @@ namespace bv { ; } ev.m_todo.reset(); + init_ranges(es); } @@ -185,7 +185,6 @@ namespace bv { auto& val_el = wval(e->get_arg(2)); for (unsigned i = 0; i < val.nw; ++i) val.fixed[i] = val_el.fixed[i] & val_th.fixed[i] & ~(val_el.bits(i) ^ val_th.bits(i)); - val.tighten_range(); } } @@ -420,6 +419,5 @@ namespace bv { UNREACHABLE(); break; } - v.tighten_range(); } } diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index 225bf9e1e..f7ce41f8b 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -99,6 +99,8 @@ namespace bv { for (unsigned i = 0; i < nw; ++i) if (0 != (fixed[i] & (m_bits[i] ^ eval[i]))) return false; + if (!in_range(eval)) + return false; for (unsigned i = 0; i < nw; ++i) m_bits[i] = eval[i]; SASSERT(well_formed()); @@ -110,6 +112,7 @@ namespace bv { auto c = m.compare(m_lo.data(), nw, m_hi.data(), nw); SASSERT(!has_overflow(bits)); // full range + if (c == 0) return true; // lo < hi: then lo <= bits & bits < hi @@ -328,13 +331,35 @@ namespace bv { bool sls_valuation::set_repair(bool try_down, bvect& dst) { for (unsigned i = 0; i < nw; ++i) dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); - bool ok = try_down ? round_down(dst) : round_up(dst); - if (!ok) - VERIFY(try_down ? round_up(dst) : round_down(dst)); - DEBUG_CODE(SASSERT(0 == (mask & (fixed[nw-1] & (m_bits[nw-1] ^ dst[nw-1])))); for (unsigned i = 0; i + 1 < nw; ++i) SASSERT(0 == (fixed[i] & (m_bits[i] ^ dst[i])));); - set(eval, dst); - SASSERT(well_formed()); - return true; + + if (in_range(dst)) { + set(eval, dst); + return true; + } + bool repaired = false; + dst.set_bw(bw); + if (m_lo < m_hi) { + for (unsigned i = bw; m_hi <= dst && !in_range(dst) && i-- > 0; ) + if (!fixed.get(i) && dst.get(i)) + dst.set(i, false); + for (unsigned i = 0; i < bw && dst < m_lo && !in_range(dst); ++i) + if (!fixed.get(i) && !dst.get(i)) + dst.set(i, true); + } + else { + for (unsigned i = 0; !in_range(dst); ++i) + if (!fixed.get(i) && !dst.get(i)) + dst.set(i, true); + for (unsigned i = bw; !in_range(dst) && i-- > 0;) + if (!fixed.get(i) && dst.get(i)) + dst.set(i, false); + } + if (in_range(dst)) { + set(eval, dst); + repaired = true; + } + dst.set_bw(0); + return repaired; } void sls_valuation::min_feasible(bvect& out) const { @@ -406,6 +431,7 @@ namespace bv { // bool sls_valuation::can_set(bvect const& new_bits) const { SASSERT(!has_overflow(new_bits)); + // verbose_stream() << "can set " << bw << " " << new_bits[0] << " " << in_range(new_bits) << "\n"; for (unsigned i = 0; i < nw; ++i) if (0 != ((new_bits[i] ^ m_bits[i]) & fixed[i])) return false; @@ -446,10 +472,8 @@ namespace bv { if (h == l) return; - verbose_stream() << "[" << l << ", " << h << "[\n"; - verbose_stream() << *this << "\n"; - - SASSERT(is_zero(fixed)); // ranges can only be added before fixed bits are set. + //verbose_stream() << "[" << l << ", " << h << "[\n"; + //verbose_stream() << *this << "\n"; if (m_lo == m_hi) { set_value(m_lo, l); @@ -481,13 +505,14 @@ namespace bv { SASSERT(!has_overflow(m_lo)); SASSERT(!has_overflow(m_hi)); - if (!in_range(m_bits)) - set(m_bits, m_lo); + + tighten_range(); SASSERT(well_formed()); - verbose_stream() << *this << "\n"; + // verbose_stream() << *this << "\n"; } // + // update bits based on ranges // tighten lo/hi based on fixed bits. // lo[bit_i] != fixedbit[bit_i] // let bit_i be most significant bit position of disagreement. @@ -502,35 +527,19 @@ namespace bv { // void sls_valuation::tighten_range() { - verbose_stream() << "tighten " << *this << "\n"; + // verbose_stream() << "tighten " << *this << "\n"; if (m_lo == m_hi) return; - for (unsigned i = bw; i-- > 0; ) { - if (!fixed.get(i)) - continue; - if (m_bits.get(i) == m_lo.get(i)) - continue; - if (m_bits.get(i)) { - m_lo.set(i, true); - for (unsigned j = i; j-- > 0; ) - m_lo.set(j, fixed.get(j) && m_bits.get(j)); - } - else { - for (unsigned j = bw; j-- > 0; ) - m_lo.set(j, fixed.get(j) && m_bits.get(j)); - } - break; - } if (!in_range(m_bits)) { - verbose_stream() << "not in range\n"; + // verbose_stream() << "not in range\n"; bool compatible = true; for (unsigned i = 0; i < nw && compatible; ++i) - compatible = 0 == (fixed[i] && (m_bits[i] ^ m_lo[i])); - verbose_stream() << (fixed[0] && (m_bits[0] ^ m_lo[0])) << "\n"; - + compatible = 0 == (fixed[i] & (m_bits[i] ^ m_lo[i])); + //verbose_stream() << (fixed[0] & (m_bits[0] ^ m_lo[0])) << "\n"; + //verbose_stream() << bw << " " << m_lo[0] << " " << m_bits[0] << "\n"; if (compatible) { - verbose_stream() << "compatible\n"; + //verbose_stream() << "compatible\n"; set(m_bits, m_lo); } else { @@ -561,6 +570,24 @@ namespace bv { set(m_bits, tmp); } } + // update lo, hi to be feasible. + + for (unsigned i = bw; i-- > 0; ) { + if (!fixed.get(i)) + continue; + if (m_bits.get(i) == m_lo.get(i)) + continue; + if (m_bits.get(i)) { + m_lo.set(i, true); + for (unsigned j = i; j-- > 0; ) + m_lo.set(j, fixed.get(j) && m_bits.get(j)); + } + else { + for (unsigned j = bw; j-- > 0; ) + m_lo.set(j, fixed.get(j) && m_bits.get(j)); + } + break; + } SASSERT(well_formed()); } diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index 8d9ff759f..f05b4c4fc 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -42,6 +42,10 @@ struct simplify_tactic::imp { m_num_steps = 0; } + void collect_statistics(statistics& st) { + st.update("rewriter.steps", m_num_steps); + } + void operator()(goal & g) { tactic_report report("simplifier", g); m_num_steps = 0; @@ -108,6 +112,11 @@ void simplify_tactic::cleanup() { new (m_imp) imp(m, p); } +void simplify_tactic::collect_statistics(statistics& st) const { + if (m_imp) + m_imp->collect_statistics(st); +} + unsigned simplify_tactic::get_num_steps() const { return m_imp->get_num_steps(); } diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index 1594b3d37..7baabb8d6 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -81,6 +81,8 @@ public: static void get_param_descrs(param_descrs & r); void collect_param_descrs(param_descrs & r) override { get_param_descrs(r); } + + void collect_statistics(statistics& st) const override; void operator()(goal_ref const & in, goal_ref_buffer & result) override; diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 4d695e300..79c1993b2 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -62,7 +62,7 @@ public: if (m_simp) pop(1); } - + /** * size(), [](), update() and inconsistent() implement the abstract interface of dependent_expr_state */ @@ -140,6 +140,12 @@ public: cleanup(); } + void collect_statistics(statistics& st) const override { + if (m_simp) + m_simp->collect_statistics(st); + st.copy(m_st); + } + void cleanup() override { if (m_simp) { m_simp->collect_statistics(m_st); @@ -151,13 +157,6 @@ public: m_dep = dependent_expr(m, m.mk_true(), nullptr, nullptr); } - void collect_statistics(statistics& st) const override { - if (m_simp) - m_simp->collect_statistics(st); - else - st.copy(m_st); - } - void reset_statistics() override { if (m_simp) m_simp->reset_statistics(); diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index ddd187337..652bf8130 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -62,7 +62,7 @@ public: */ virtual void operator()(goal_ref const & in, goal_ref_buffer& result) = 0; - virtual void collect_statistics(statistics & st) const { } + virtual void collect_statistics(statistics& st) const { } virtual void reset_statistics() {} virtual void cleanup() = 0; virtual void reset() { cleanup(); } @@ -130,6 +130,7 @@ public: void cleanup() override {} tactic * translate(ast_manager & m) override { return this; } char const* name() const override { return "skip"; } + void collect_statistics(statistics& st) const override {} }; tactic * mk_skip_tactic(); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 5b1ea9587..0b8189e8d 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -1190,6 +1190,9 @@ public: tactic * translate(ast_manager & m) override { return this; } + + void collect_statistics(statistics& st) const override { + } }; tactic * fail_if(probe * p) { @@ -1216,6 +1219,7 @@ public: } tactic * translate(ast_manager & m) override { return translate_core(m); } + }; class if_no_unsat_cores_tactical : public unary_tactical { From 8679c08010fa180e165dbdf658ed09e8a5304898 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Mar 2024 03:42:58 -0800 Subject: [PATCH 46/69] fix test Signed-off-by: Nikolaj Bjorner --- src/test/sls_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/sls_test.cpp b/src/test/sls_test.cpp index 9d0b569a7..d99035398 100644 --- a/src/test/sls_test.cpp +++ b/src/test/sls_test.cpp @@ -30,7 +30,7 @@ namespace bv { es.push_back(e); sls_eval ev(m); ev.init_eval(es, value); - ev.init_fixed(es); + ev.tighten_range(es); th_rewriter rw(m); expr_ref r(e, m); rw(r); @@ -144,7 +144,7 @@ namespace bv { es.push_back(m.is_false(r) ? m.mk_not(e2) : e2); sls_eval ev(m); ev.init_eval(es, value); - ev.init_fixed(es); + ev.tighten_range(es); if (m.is_bool(e1)) { SASSERT(m.is_true(r) || m.is_false(r)); From 657aaf9a0fd9d6e427aca3f8228e77fd3472927a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Mar 2024 10:15:44 -0800 Subject: [PATCH 47/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls_eval.cpp | 2 +- src/ast/sls/sls_valuation.cpp | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index 592c92b1c..cc5911905 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -976,7 +976,7 @@ namespace bv { bool sls_eval::try_repair_band(bvect const& e, bvval& a, bvval const& b) { for (unsigned i = 0; i < a.nw; ++i) - m_tmp[i] = (e[i] & ~a.fixed[i]) | (~b.bits()[i] & ~a.fixed[i] & random_bits()); + m_tmp[i] = ~a.fixed[i] & (e[i] | (~b.bits()[i] & random_bits())); return a.set_repair(random_bool(), m_tmp); } diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index f7ce41f8b..b656a341b 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -347,7 +347,7 @@ namespace bv { dst.set(i, true); } else { - for (unsigned i = 0; !in_range(dst); ++i) + for (unsigned i = 0; i < bw && !in_range(dst); ++i) if (!fixed.get(i) && !dst.get(i)) dst.set(i, true); for (unsigned i = bw; !in_range(dst) && i-- > 0;) @@ -431,7 +431,6 @@ namespace bv { // bool sls_valuation::can_set(bvect const& new_bits) const { SASSERT(!has_overflow(new_bits)); - // verbose_stream() << "can set " << bw << " " << new_bits[0] << " " << in_range(new_bits) << "\n"; for (unsigned i = 0; i < nw; ++i) if (0 != ((new_bits[i] ^ m_bits[i]) & fixed[i])) return false; @@ -548,10 +547,8 @@ namespace bv { set(tmp, m_lo); unsigned max_diff = bw; for (unsigned i = 0; i < bw; ++i) { - if (fixed.get(i) && (m_bits.get(i) ^ m_lo.get(i))) { - tmp.set(i, m_bits.get(i)); - max_diff = i; - } + if (fixed.get(i) && (m_bits.get(i) ^ m_lo.get(i))) + max_diff = i; } SASSERT(max_diff != bw); From 531bda39ac7f97656c831b1b6ed18f1ceb232ad5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Mar 2024 10:15:14 -0800 Subject: [PATCH 48/69] fix alias bug --- src/ast/sls/bv_sls_eval.cpp | 21 +++++++++++++++------ src/ast/sls/sls_valuation.cpp | 24 ++++++++++++------------ src/ast/sls/sls_valuation.h | 11 ++++++----- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index cc5911905..a70bc7261 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -1043,8 +1043,16 @@ namespace bv { if (b.is_zero()) { a.get_variant(m_tmp, m_rand); return a.set_repair(random_bool(), m_tmp); - } - + } + +#if 0 + verbose_stream() << "solve for " << e << "\n"; + + rational r = e.get_value(e.nw); + rational root; + verbose_stream() << r.is_int_perfect_square(root) << "\n"; +#endif + auto& x = m_tmp; auto& y = m_tmp2; @@ -1055,7 +1063,8 @@ namespace bv { auto& nexta = m_nexta; auto& nextb = m_nextb; auto& aux = m_aux; - + auto bw = b.bw; + // x*ta + y*tb = x @@ -1071,10 +1080,11 @@ namespace bv { y[a.nw] = 0; x[a.nw] = 0; + a.set_bw((a.nw + 1)* 8 * sizeof(digit_t)); y.set_bw(a.bw); // enable comparisons a.set_zero(x); - x.set(b.bw, true); // x = 2 ^ b.bw + x.set(bw, true); // x = 2 ^ b.bw a.set_one(ta); a.set_zero(tb); @@ -1099,11 +1109,10 @@ namespace bv { a.set(tb, aux); // tb := aux } - a.set_bw(b.bw); + a.set_bw(bw); y.set_bw(0); // x*a + y*b = 1 - tb.set_bw(b.bw); tb.set_bw(0); #if Z3DEBUG b.get(y); diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index b656a341b..aeeb392e2 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -74,6 +74,15 @@ namespace bv { return out; } + rational bvect::get_value(unsigned nw) const { + rational p(1), r(0); + for (unsigned i = 0; i < nw; ++i) { + r += p * rational((*this)[i]); + p *= rational::power_of_two(8 * sizeof(digit_t)); + } + return r; + } + sls_valuation::sls_valuation(unsigned bw) { set_bw(bw); m_lo.set_bw(bw); @@ -347,7 +356,7 @@ namespace bv { dst.set(i, true); } else { - for (unsigned i = 0; i < bw && !in_range(dst); ++i) + for (unsigned i = 0; !in_range(dst) && i < bw; ++i) if (!fixed.get(i) && !dst.get(i)) dst.set(i, true); for (unsigned i = bw; !in_range(dst) && i-- > 0;) @@ -398,15 +407,6 @@ namespace bv { clear_overflow_bits(bits); } - rational sls_valuation::get_value(bvect const& bits) const { - rational p(1), r(0); - for (unsigned i = 0; i < nw; ++i) { - r += p * rational(bits[i]); - p *= rational::power_of_two(8 * sizeof(digit_t)); - } - return r; - } - void sls_valuation::get(bvect& dst) const { m_bits.copy_to(nw, dst); } @@ -479,8 +479,8 @@ namespace bv { set_value(m_hi, h); } else { - auto old_lo = get_value(m_lo); - auto old_hi = get_value(m_hi); + auto old_lo = lo(); + auto old_hi = hi(); if (old_lo < old_hi) { if (old_lo < l && l < old_hi) set_value(m_lo, l), diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index cbe1a35a4..e79ac959c 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -60,6 +60,8 @@ namespace bv { return bw; } + rational get_value(unsigned nw) const; + friend bool operator==(bvect const& a, bvect const& b); friend bool operator<(bvect const& a, bvect const& b); friend bool operator>(bvect const& a, bvect const& b); @@ -96,7 +98,6 @@ namespace bv { bvect m_lo, m_hi; // range assignment to bit-vector, as wrap-around interval unsigned mask; - rational get_value(bvect const& bits) const; bool round_up(bvect& dst) const; bool round_down(bvect& dst) const; @@ -131,10 +132,10 @@ namespace bv { void set_value(bvect& bits, rational const& r); - rational get_value() const { return get_value(m_bits); } - rational get_eval() const { return get_value(eval); } - rational lo() const { return get_value(m_lo); } - rational hi() const { return get_value(m_hi); } + rational get_value() const { return m_bits.get_value(nw); } + rational get_eval() const { return eval.get_value(nw); } + rational lo() const { return m_lo.get_value(nw); } + rational hi() const { return m_hi.get_value(nw); } void get(bvect& dst) const; From d6f522e205a03f5d6c59fa415cf59d182e2b3e84 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Mar 2024 02:53:47 -0800 Subject: [PATCH 49/69] na Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bv_sls.cpp | 7 ++-- src/ast/sls/bv_sls_eval.cpp | 64 ++++++++++++++++++++++++----------- src/ast/sls/bv_sls_eval.h | 6 ++-- src/ast/sls/sls_valuation.cpp | 29 +++++++++++++++- src/ast/sls/sls_valuation.h | 4 +++ 5 files changed, 83 insertions(+), 27 deletions(-) diff --git a/src/ast/sls/bv_sls.cpp b/src/ast/sls/bv_sls.cpp index 108abd891..f80a362ba 100644 --- a/src/ast/sls/bv_sls.cpp +++ b/src/ast/sls/bv_sls.cpp @@ -70,7 +70,7 @@ namespace bv { void sls::reinit_eval() { std::function eval = [&](expr* e, unsigned i) { auto should_keep = [&]() { - return m_rand() % 100 >= 98; + return m_rand() % 100 <= 92; }; if (m.is_bool(e)) { if (m_eval.is_fixed0(e) || should_keep()) @@ -127,11 +127,12 @@ namespace bv { if (!e) return l_true; - ++m_stats.m_moves; trace_repair(down, e); - if (down) + ++m_stats.m_moves; + + if (down) try_repair_down(e); else try_repair_up(e); diff --git a/src/ast/sls/bv_sls_eval.cpp b/src/ast/sls/bv_sls_eval.cpp index a70bc7261..4b7bf9546 100644 --- a/src/ast/sls/bv_sls_eval.cpp +++ b/src/ast/sls/bv_sls_eval.cpp @@ -30,7 +30,7 @@ namespace bv { continue; app* a = to_app(e); if (bv.is_bv(e)) - add_bit_vector(e); + add_bit_vector(a); if (a->get_family_id() == basic_family_id) init_eval_basic(a); else if (a->get_family_id() == bv.get_family_id()) @@ -40,7 +40,7 @@ namespace bv { auto& v = wval(e); for (unsigned i = 0; i < v.bw; ++i) m_tmp.set(i, eval(e, i)); - v.set(m_tmp); + v.set_repair(random_bool(), m_tmp); } else if (m.is_bool(e)) m_eval.setx(e->get_id(), eval(e, 0), false); @@ -78,16 +78,21 @@ namespace bv { return m_todo; } - bool sls_eval::add_bit_vector(expr* e) { - auto bw = bv.get_bv_size(e); + bool sls_eval::add_bit_vector(app* e) { m_values.reserve(e->get_id() + 1); if (m_values.get(e->get_id())) return false; - m_values.set(e->get_id(), alloc_valuation(bw)); + auto v = alloc_valuation(e); + m_values.set(e->get_id(), v); + if (bv.is_sign_ext(e)) { + unsigned p = e->get_parameter(0).get_int(); + v->set_signed(p); + } return true; } - sls_valuation* sls_eval::alloc_valuation(unsigned bit_width) { + sls_valuation* sls_eval::alloc_valuation(app* e) { + auto bit_width = bv.get_bv_size(e); auto* r = alloc(sls_valuation, bit_width); while (m_tmp.size() < 2 * r->nw) { m_tmp.push_back(0); @@ -905,8 +910,14 @@ namespace bv { } bool sls_eval::try_repair_eq(bool is_true, bvval& a, bvval const& b) { - if (is_true) - return a.try_set(b.bits()); + if (is_true) { + if (m_rand() % 20 != 0) + if (a.try_set(b.bits())) + return true; + + a.get_variant(m_tmp, m_rand); + return a.set_repair(random_bool(), m_tmp); + } else { bool try_above = m_rand() % 2 == 0; if (try_above) { @@ -1004,22 +1015,26 @@ namespace bv { // If this fails, set a to a random value // bool sls_eval::try_repair_add(bvect const& e, bvval& a, bvval const& b) { - a.set_sub(m_tmp, e, b.bits()); - if (a.try_set(m_tmp)) - return true; + if (m_rand() % 20 != 0) { + a.set_sub(m_tmp, e, b.bits()); + if (a.try_set(m_tmp)) + return true; + } a.get_variant(m_tmp, m_rand); return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_sub(bvect const& e, bvval& a, bvval & b, unsigned i) { - if (i == 0) - // e = a - b -> a := e + b - a.set_add(m_tmp, e, b.bits()); - else - // b := a - e - b.set_sub(m_tmp, a.bits(), e); - if (a.try_set(m_tmp)) - return true; + if (m_rand() % 20 != 0) { + if (i == 0) + // e = a - b -> a := e + b + a.set_add(m_tmp, e, b.bits()); + else + // b := a - e + b.set_sub(m_tmp, a.bits(), e); + if (a.try_set(m_tmp)) + return true; + } // fall back to a random value a.get_variant(m_tmp, m_rand); return a.set_repair(random_bool(), m_tmp); @@ -1045,6 +1060,11 @@ namespace bv { return a.set_repair(random_bool(), m_tmp); } + if (m_rand() % 20 == 0) { + a.get_variant(m_tmp, m_rand); + return a.set_repair(random_bool(), m_tmp); + } + #if 0 verbose_stream() << "solve for " << e << "\n"; @@ -1125,7 +1145,11 @@ namespace bv { if (parity_e > 0 && parity_b > 0) b.shift_right(m_tmp2, std::min(parity_b, parity_e)); a.set_mul(m_tmp, tb, m_tmp2); - return a.set_repair(random_bool(), m_tmp); + if (a.set_repair(random_bool(), m_tmp)) + return true; + + a.get_variant(m_tmp, m_rand); + return a.set_repair(random_bool(), m_tmp); } bool sls_eval::try_repair_bnot(bvect const& e, bvval& a) { diff --git a/src/ast/sls/bv_sls_eval.h b/src/ast/sls/bv_sls_eval.h index 42e67609d..5422d5b7c 100644 --- a/src/ast/sls/bv_sls_eval.h +++ b/src/ast/sls/bv_sls_eval.h @@ -59,8 +59,8 @@ namespace bv { * Register e as a bit-vector. * Return true if not already registered, false if already registered. */ - bool add_bit_vector(expr* e); - sls_valuation* alloc_valuation(unsigned bit_width); + bool add_bit_vector(app* e); + sls_valuation* alloc_valuation(app* e); bool bval1_basic(app* e) const; bool bval1_bv(app* e) const; @@ -143,7 +143,7 @@ namespace bv { sls_valuation& wval(expr* e) const; - bool is_fixed0(expr* e) const { return m_fixed[e->get_id()]; } + bool is_fixed0(expr* e) const { return m_fixed.get(e->get_id(), false); } /** * Retrieve evaluation based on immediate children. diff --git a/src/ast/sls/sls_valuation.cpp b/src/ast/sls/sls_valuation.cpp index aeeb392e2..3160e5cf5 100644 --- a/src/ast/sls/sls_valuation.cpp +++ b/src/ast/sls/sls_valuation.cpp @@ -307,18 +307,21 @@ namespace bv { void sls_valuation::round_down(bvect& dst, std::function const& is_feasible) { for (unsigned i = bw; !is_feasible(dst) && i-- > 0; ) if (!fixed.get(i) && dst.get(i)) - dst.set(i, false); + dst.set(i, false); + repair_sign_bits(dst); } void sls_valuation::round_up(bvect& dst, std::function const& is_feasible) { for (unsigned i = 0; !is_feasible(dst) && i < bw; ++i) if (!fixed.get(i) && !dst.get(i)) dst.set(i, true); + repair_sign_bits(dst); } void sls_valuation::set_random_above(bvect& dst, random_gen& r) { for (unsigned i = 0; i < nw; ++i) dst[i] = dst[i] | (random_bits(r) & ~fixed[i]); + repair_sign_bits(dst); } void sls_valuation::set_random_below(bvect& dst, random_gen& r) { @@ -335,12 +338,14 @@ namespace bv { for (unsigned i = 0; i < idx; ++i) if (!fixed.get(i)) dst.set(i, r() % 2 == 0); + repair_sign_bits(dst); } bool sls_valuation::set_repair(bool try_down, bvect& dst) { for (unsigned i = 0; i < nw; ++i) dst[i] = (~fixed[i] & dst[i]) | (fixed[i] & m_bits[i]); + repair_sign_bits(dst); if (in_range(dst)) { set(eval, dst); return true; @@ -363,6 +368,7 @@ namespace bv { if (!fixed.get(i) && dst.get(i)) dst.set(i, false); } + repair_sign_bits(dst); if (in_range(dst)) { set(eval, dst); repaired = true; @@ -378,6 +384,7 @@ namespace bv { for (unsigned i = 0; i < nw; ++i) out[i] = fixed[i] & m_bits[i]; } + repair_sign_bits(out); SASSERT(!has_overflow(out)); } @@ -390,6 +397,7 @@ namespace bv { for (unsigned i = 0; i < nw; ++i) out[i] = ~fixed[i] | m_bits[i]; } + repair_sign_bits(out); SASSERT(!has_overflow(out)); } @@ -421,9 +429,28 @@ namespace bv { void sls_valuation::get_variant(bvect& dst, random_gen& r) const { for (unsigned i = 0; i < nw; ++i) dst[i] = (random_bits(r) & ~fixed[i]) | (fixed[i] & m_bits[i]); + repair_sign_bits(dst); clear_overflow_bits(dst); } + void sls_valuation::repair_sign_bits(bvect& dst) const { + if (m_signed_prefix == 0) + return; + bool sign = dst.get(bw - 1); + for (unsigned i = bw; i-- >= bw - m_signed_prefix; ) { + if (dst.get(i) != sign) { + if (fixed.get(i)) { + for (unsigned i = bw; i-- >= bw - m_signed_prefix; ) + if (!fixed.get(i)) + dst.set(i, !sign); + return; + } + else + dst.set(i, sign); + } + } + } + // // new_bits != bits => ~fixed // 0 = (new_bits ^ bits) & fixed diff --git a/src/ast/sls/sls_valuation.h b/src/ast/sls/sls_valuation.h index e79ac959c..dcabf04c0 100644 --- a/src/ast/sls/sls_valuation.h +++ b/src/ast/sls/sls_valuation.h @@ -96,11 +96,14 @@ namespace bv { protected: bvect m_bits; bvect m_lo, m_hi; // range assignment to bit-vector, as wrap-around interval + unsigned m_signed_prefix = 0; unsigned mask; bool round_up(bvect& dst) const; bool round_down(bvect& dst) const; + void repair_sign_bits(bvect& dst) const; + public: unsigned bw; // bit-width @@ -111,6 +114,7 @@ namespace bv { sls_valuation(unsigned bw); void set_bw(unsigned bw); + void set_signed(unsigned prefix) { m_signed_prefix = prefix; } unsigned num_bytes() const { return (bw + 7) / 8; } From e8c8d8aa7dca9cfa48b3c9b51cd2508d17fc9931 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Tue, 5 Mar 2024 13:38:12 -0800 Subject: [PATCH 50/69] Put in workaround to rename manylinux_arm64 to manylinux_aarch64 (#7149) --- src/api/python/setup.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 8a8a49dc5..bc0acead8 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -298,7 +298,14 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: if arch == 'x64': plat_name = 'manylinux2014_x86_64' elif arch == 'arm64': - plat_name = 'manylinux2014_arm64' + # context on why are we match on arm64 + # but use aarch64 on the plat_name is + # due to a workaround current python + # legacy build doesn't support aarch64 + # so using the currently supported arm64 + # build and simply rename it to aarch64 + # see full context on #7148 + plat_name = 'manylinux2014_aarch64' else: plat_name = 'manylinux2014_i686' elif distos == 'linux' and os_id == 'alpine': From 017367d7af4b834c5062ceeba95668abbbcf2fa7 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Wed, 6 Mar 2024 08:27:04 -0800 Subject: [PATCH 51/69] Handle cross compile within manylinux (#7150) --- scripts/mk_unix_dist.py | 14 +++++++++++++- scripts/nightly.yaml | 6 ++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 3b1e71391..55c8ccf31 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -118,7 +118,9 @@ def check_build_dir(path): # Create a build directory using mk_make.py def mk_build_dir(path): + global LINUX_X64 if not check_build_dir(path) or FORCE_MK: + env = os.environ opts = [sys.executable, os.path.join('scripts', 'mk_make.py'), "-b", path, "--staticlib"] if DOTNET_CORE_ENABLED: opts.append('--dotnet') @@ -133,7 +135,17 @@ def mk_build_dir(path): opts.append('--python') if mk_util.IS_ARCH_ARM64: opts.append('--arm64=true') - if subprocess.call(opts) != 0: + if mk_util.IS_ARCH_ARM64 and LINUX_X64: + # we are machine x64 but build against arm64 + # so we have to do cross compiling + # the cross compiler is download from ARM GNU + # toolchain + myvar = { + "CC": "aarch64-none-linux-gnu-gcc", + "CXX": "aarch64-none-linux-gnu-g++" + } + env.update(myvar) + if subprocess.call(opts, env=env) != 0: raise MKException("Failed to generate build directory at '%s'" % path) # Create build directories diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 77ca31458..062195dae 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -203,6 +203,12 @@ stages: vmImage: "ubuntu-latest" container: "quay.io/pypa/manylinux2014_x86_64:latest" steps: + - script: yum install wget + - script: wget -q -O /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=22c39fc25e5541818967b4ff5a09ef3e&hash=E7676169CE35FC2AAECF4C121E426083871CA6E5' + - script: tar xf /tmp/arm-toolchain.tar.xz -C /arm-toolchain/ --strip-components=1 + - script: echo '##vso[task.prependpath]/arm-toolchain/bin' + - script: echo $PATH + - script: stat /arm-toolchain/bin/aarch64-none-linux-gnu-gcc - task: PythonScript@0 displayName: Build inputs: From aad8cbdd9d26b3c2b73b376bf8da7c78420f6cb1 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Wed, 6 Mar 2024 13:21:17 -0800 Subject: [PATCH 52/69] Add LinuxBuildsArm64 ci azure-pipelines for testing (#7152) --- azure-pipelines.yml | 41 +++++++++++++++++++++++++++++++++++++++++ scripts/nightly.yaml | 10 +++++----- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d9d2ab2b2..6fcb2d1c1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,6 +43,47 @@ jobs: - ${{if eq(variables['runRegressions'], 'True')}}: - template: scripts/test-regressions.yml +- job: LinuxBuildsArm64 + displayName: "ManyLinux ARM64 build" + variables: + name: ManyLinux + python: "/opt/python/cp37-cp37m/bin/python" + pool: + vmImage: "ubuntu-latest" + container: "quay.io/pypa/manylinux2014_x86_64:latest" + steps: + - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=22c39fc25e5541818967b4ff5a09ef3e&hash=E7676169CE35FC2AAECF4C121E426083871CA6E5' + - script: mkdir -p /tmp/arm-toolchain/ + - script: tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 + - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/bin' + - script: echo $PATH + - script: stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc + - task: PythonScript@0 + displayName: Build + inputs: + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --nodotnet --nojava --arch=arm64 + pythonInterpreter: $(python) + - script: git clone https://github.com/z3prover/z3test z3test + displayName: 'Clone z3test' + - task: PythonScript@0 + displayName: Test + inputs: + scriptSource: 'filepath' + scriptPath: z3test/scripts/test_benchmarks.py + arguments: build-dist/z3 z3test/regressions/smt2 + pythonInterpreter: $(python) + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'ManyLinuxBuildArm64' + targetPath: $(Build.ArtifactStagingDirectory) + - job: "Ubuntu20OCaml" displayName: "Ubuntu 20 with OCaml" pool: diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 062195dae..0c06f3457 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -203,12 +203,12 @@ stages: vmImage: "ubuntu-latest" container: "quay.io/pypa/manylinux2014_x86_64:latest" steps: - - script: yum install wget - - script: wget -q -O /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=22c39fc25e5541818967b4ff5a09ef3e&hash=E7676169CE35FC2AAECF4C121E426083871CA6E5' - - script: tar xf /tmp/arm-toolchain.tar.xz -C /arm-toolchain/ --strip-components=1 - - script: echo '##vso[task.prependpath]/arm-toolchain/bin' + - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=22c39fc25e5541818967b4ff5a09ef3e&hash=E7676169CE35FC2AAECF4C121E426083871CA6E5' + - script: mkdir -p /tmp/arm-toolchain/ + - script: tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 + - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/bin' - script: echo $PATH - - script: stat /arm-toolchain/bin/aarch64-none-linux-gnu-gcc + - script: stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc - task: PythonScript@0 displayName: Build inputs: From 620efbb67b6c43457620daebcce7faac92baaa26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2024 13:53:43 -0800 Subject: [PATCH 53/69] add aacrhc Signed-off-by: Nikolaj Bjorner --- src/api/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index bc0acead8..5faf5aad1 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -297,7 +297,7 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: elif distos == 'glibc': if arch == 'x64': plat_name = 'manylinux2014_x86_64' - elif arch == 'arm64': + elif arch == 'arm64' or arch == 'aarch64': # context on why are we match on arm64 # but use aarch64 on the plat_name is # due to a workaround current python From 364da191223cf49e5b18fd4cb30ac9193e23555b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2024 13:54:28 -0800 Subject: [PATCH 54/69] remove test Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 0c06f3457..294f4f947 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -216,15 +216,6 @@ stages: scriptPath: scripts/mk_unix_dist.py arguments: --nodotnet --nojava --arch=arm64 pythonInterpreter: $(python) - - script: git clone https://github.com/z3prover/z3test z3test - displayName: 'Clone z3test' - - task: PythonScript@0 - displayName: Test - inputs: - scriptSource: 'filepath' - scriptPath: z3test/scripts/test_benchmarks.py - arguments: build-dist/z3 z3test/regressions/smt2 - pythonInterpreter: $(python) - task: CopyFiles@2 inputs: sourceFolder: dist From e873664fe804ac5bc3831340928fa40d4816887a Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Wed, 6 Mar 2024 20:14:06 -0800 Subject: [PATCH 55/69] Downgrade arm cross compile toolchain to glibc 2.34 (#7153) --- azure-pipelines.yml | 12 ++---------- scripts/mk_unix_dist.py | 20 ++++++++++++++++++-- scripts/nightly.yaml | 3 ++- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6fcb2d1c1..b3bc0f226 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -52,10 +52,11 @@ jobs: vmImage: "ubuntu-latest" container: "quay.io/pypa/manylinux2014_x86_64:latest" steps: - - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=22c39fc25e5541818967b4ff5a09ef3e&hash=E7676169CE35FC2AAECF4C121E426083871CA6E5' + - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz?rev=33c6e30e5ac64e6dba8f0431f2c35f1b&hash=9918A05BF47621B632C7A5C8D2BB438FB80A4480' - script: mkdir -p /tmp/arm-toolchain/ - script: tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/bin' + - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin' - script: echo $PATH - script: stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc - task: PythonScript@0 @@ -65,15 +66,6 @@ jobs: scriptPath: scripts/mk_unix_dist.py arguments: --nodotnet --nojava --arch=arm64 pythonInterpreter: $(python) - - script: git clone https://github.com/z3prover/z3test z3test - displayName: 'Clone z3test' - - task: PythonScript@0 - displayName: Test - inputs: - scriptSource: 'filepath' - scriptPath: z3test/scripts/test_benchmarks.py - arguments: build-dist/z3 z3test/regressions/smt2 - pythonInterpreter: $(python) - task: CopyFiles@2 inputs: sourceFolder: dist diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 55c8ccf31..d967e9109 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -171,12 +171,22 @@ def mk_z3(): return 1 def get_os_name(): + global LINUX_X64 if OS_NAME is not None: return OS_NAME import platform basic = os.uname()[0].lower() if basic == 'linux': - dist = platform.libc_ver() + if mk_util.IS_ARCH_ARM64 and LINUX_X64: + # handle cross compiling + # example: 'ldd (GNU) 2.34' + lines = subprocess.check_output(["ldd", "--version"]).decode('ascii') + first_line = lines.split("\n")[0] + ldd_version = first_line.split()[-1] + # coerce the format to platform.libc_ver() return type + dist = ('glibc', ldd_version) + else: + dist = platform.libc_ver() if len(dist) == 2 and len(dist[0]) > 0 and len(dist[1]) > 0: return '%s-%s' % (dist[0].lower(), dist[1].lower()) else: @@ -199,8 +209,14 @@ def get_os_name(): return basic def get_z3_name(): + import platform as platform_module + # Note that the platform name this function return + # has to work together with setup.py + # It's not the typical output from platform.machine() major, minor, build, revision = get_version() - if mk_util.IS_ARCH_ARM64: + if mk_util.IS_ARCH_ARM64 or platform_module.machine() == "aarch64": + # the second case handle native build on aarch64 + # TODO: we don't handle cross compile on host aarch64 to target x64 platform = "arm64" elif sys.maxsize >= 2**32: platform = "x64" diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 294f4f947..51533dd8e 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -203,10 +203,11 @@ stages: vmImage: "ubuntu-latest" container: "quay.io/pypa/manylinux2014_x86_64:latest" steps: - - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=22c39fc25e5541818967b4ff5a09ef3e&hash=E7676169CE35FC2AAECF4C121E426083871CA6E5' + - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz?rev=33c6e30e5ac64e6dba8f0431f2c35f1b&hash=9918A05BF47621B632C7A5C8D2BB438FB80A4480' - script: mkdir -p /tmp/arm-toolchain/ - script: tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/bin' + - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin' - script: echo $PATH - script: stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc - task: PythonScript@0 From 7b7084d3731945f3ed3d696c7cfd13c34e9f8704 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Thu, 7 Mar 2024 09:11:47 -0800 Subject: [PATCH 56/69] Add LinuxBuildsArm64 to python wheels in release (#7155) --- scripts/release.yml | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/scripts/release.yml b/scripts/release.yml index 083e58aee..3c83e719e 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -199,6 +199,39 @@ stages: artifactName: 'ManyLinuxBuild' targetPath: $(Build.ArtifactStagingDirectory) + - job: LinuxBuildsArm64 + displayName: "ManyLinux ARM64 build" + variables: + name: ManyLinux + python: "/opt/python/cp37-cp37m/bin/python" + pool: + vmImage: "ubuntu-latest" + container: "quay.io/pypa/manylinux2014_x86_64:latest" + steps: + - script: curl -L -o /tmp/arm-toolchain.tar.xz 'https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz?rev=33c6e30e5ac64e6dba8f0431f2c35f1b&hash=9918A05BF47621B632C7A5C8D2BB438FB80A4480' + - script: mkdir -p /tmp/arm-toolchain/ + - script: tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1 + - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/bin' + - script: echo '##vso[task.prependpath]/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin' + - script: echo $PATH + - script: stat /tmp/arm-toolchain/bin/aarch64-none-linux-gnu-gcc + - task: PythonScript@0 + displayName: Build + inputs: + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --nodotnet --nojava --arch=arm64 + pythonInterpreter: $(python) + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'ManyLinuxBuildArm64' + targetPath: $(Build.ArtifactStagingDirectory) + - template: build-win-signed.yml parameters: ReleaseVersion: $(ReleaseVersion) @@ -470,7 +503,8 @@ stages: path: $(Agent.TempDirectory) - script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip - script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip - - script: cd $(Agent.TempDirectory); mkdir libc-bin; cd libc-bin; unzip ../*glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-x64-bin; cd libc-x64-bin; unzip ../*x64-glibc*.zip + - script: cd $(Agent.TempDirectory); mkdir libc-arm64-bin; cd libc-arm64-bin; unzip ../*arm64-glibc*.zip - script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip - script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip - script: python3 -m pip install --user -U setuptools wheel @@ -478,7 +512,8 @@ stages: # take a look at this PREMIUM HACK I came up with to get around the fact that the azure variable syntax overloads the bash syntax for subshells - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/osx-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel + - script: cd src/api/python; echo $(Agent.TempDirectory)/libc-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel - task: PublishPipelineArtifact@0 From 6254844e2d86edf9515a2999c1dc566966a577dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Mar 2024 09:14:34 -0800 Subject: [PATCH 57/69] update release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9b041c07e..f19f2bf64 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,6 +10,10 @@ Version 4.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.13 +============ +- add ARM64 wheels for Python, thanks to Steven Moy, smoy + Version 4.12.6 ============== - remove expensive rewrite that coalesces adjacent stores From f9ce332b54332460d8705279127f9b2982af9db7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Mar 2024 09:15:34 -0800 Subject: [PATCH 58/69] update release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f19f2bf64..3830f566f 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,8 +10,8 @@ Version 4.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. -Version 4.13 -============ +Version 4.13.0 +============== - add ARM64 wheels for Python, thanks to Steven Moy, smoy Version 4.12.6 From 3049f578a8f98a0b0992eca193afe57a73b30ca3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Mar 2024 10:25:16 -0800 Subject: [PATCH 59/69] add download of Arm64 to python packaging Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/release.yml b/scripts/release.yml index 3c83e719e..7fcd93b16 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -491,6 +491,11 @@ stages: inputs: artifact: 'ManyLinuxBuild' path: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: 'Download ManyLinux Arm64 Build' + inputs: + artifact: 'ManyLinuxBuildArm64' + path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 displayName: 'Download Win32 Build' inputs: From a4ecaf1ff513ada29d00f3234cf4a567393be36e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Mar 2024 11:22:08 -0800 Subject: [PATCH 60/69] increment version number Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 2 +- scripts/release.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba3ec7bce..cdccb8e4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.13.0.0 LANGUAGES CXX) +project(Z3 VERSION 4.13.1.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 2805cbaf1..d76e03ba6 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 13, 0, 0) # express a default build version or pick up ci build version + set_version(4, 13, 0, 1) # express a default build version or pick up ci build version # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 51533dd8e..00e27507e 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,7 +1,7 @@ variables: Major: '4' Minor: '13' - Patch: '0' + Patch: '1' ReleaseVersion: $(Major).$(Minor).$(Patch) AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) NightlyVersion: $(AssemblyVersion)-$(Build.buildId) diff --git a/scripts/release.yml b/scripts/release.yml index 7fcd93b16..8f1242f82 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.13.0' + ReleaseVersion: '4.13.1' stages: From dcaacf5e9bc8876c88746fbd2bdd99be875a2703 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Mar 2024 15:21:26 -0800 Subject: [PATCH 61/69] add rewrite glue for instantiating equalities, #7154 Signed-off-by: Nikolaj Bjorner --- src/ast/macros/macro_manager.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index bbe7f245c..b7c94b1b5 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -319,14 +319,21 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { if (m.proofs_enabled()) { expr_ref instance = s(q->get_expr(), num, subst_args.data()); expr* eq, * lhs, * rhs; + + expr* q_inst = m.mk_or(m.mk_not(q), instance); + proof * qi_pr = m.mk_quant_inst(q_inst, num, subst_args.data()); if (m.is_not(instance, eq) && m.is_eq(eq, lhs, rhs)) { + expr_ref instance2(m); if (revert) - instance = m.mk_eq(m.mk_not(lhs), rhs); + instance2 = m.mk_eq(m.mk_not(lhs), rhs); else - instance = m.mk_eq(lhs, m.mk_not(rhs)); + instance2 = m.mk_eq(lhs, m.mk_not(rhs)); + expr* q_inst2 = m.mk_or(m.mk_not(q), instance2); + proof* eq_pr = m.mk_rewrite(q_inst, q_inst2); + qi_pr = m.mk_modus_ponens(qi_pr, eq_pr); + instance = instance2; } SASSERT(m.is_eq(instance)); - proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.data()); proof * q_pr = mm.m_decl2macro_pr.find(d); proof * prs[2] = { qi_pr, q_pr }; p = m.mk_unit_resolution(2, prs); From 361e04a18e3ca460fdfe8c1d0b34ac1a120106c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Mar 2024 10:27:12 -0800 Subject: [PATCH 62/69] port fixes to intblast Signed-off-by: Nikolaj Bjorner --- src/math/lp/lar_solver.cpp | 12 +++++++++++- src/math/lp/lar_solver.h | 1 + src/sat/smt/arith_axioms.cpp | 12 ++++++++---- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index ef61c2209..9272e0298 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1531,7 +1531,7 @@ namespace lp { SASSERT(all_vars_are_registered(coeffs)); lar_term* t = new lar_term(coeffs); subst_known_terms(t); - SASSERT(t->is_empty() == false); + SASSERT (!t->is_empty()); m_terms.push_back(t); lpvar ret = A_r().column_count(); add_row_from_term_no_constraint(t, ext_i); @@ -2266,12 +2266,22 @@ namespace lp { return false; } + bool lar_solver::are_equal(lpvar j, lpvar k) { + vector> coeffs; + coeffs.push_back(std::make_pair(mpq(1), j)); + coeffs.push_back(std::make_pair(mpq(-1), k)); + lar_term t(coeffs); + subst_known_terms(&t); + return t.is_empty(); + } + std::pair lar_solver::add_equality(lpvar j, lpvar k) { vector> coeffs; coeffs.push_back(std::make_pair(mpq(1), j)); coeffs.push_back(std::make_pair(mpq(-1), k)); unsigned ej = add_term(coeffs, UINT_MAX); // UINT_MAX is the external null var + if (get_column_value(j) != get_column_value(k)) set_status(lp_status::UNKNOWN); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 4d71d0181..ec40fcb24 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -559,6 +559,7 @@ public: return m_mpq_lar_core_solver.m_r_solver.calc_current_x_is_feasible_include_non_basis(); } + bool are_equal(lpvar j, lpvar k); std::pair add_equality(lpvar j, lpvar k); u_dependency* get_bound_constraint_witnesses_for_column(unsigned j) { diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index b2dd5e969..7270e7080 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -331,15 +331,17 @@ namespace arith { expr_ref x(a.mk_mod(_x, a.mk_int(N)), m); expr_ref y(a.mk_mod(_y, a.mk_int(N)), m); + // 0 <= n < 2^sz + + add_clause(mk_literal(a.mk_ge(n, a.mk_int(0)))); + add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1)))); + if (a.is_band(n)) { - - // 0 <= x&y < 2^sz + // x&y <= x // x&y <= y // TODO? x = y => x&y = x - add_clause(mk_literal(a.mk_ge(n, a.mk_int(0)))); - add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1)))); add_clause(mk_literal(a.mk_le(n, x))); add_clause(mk_literal(a.mk_le(n, y))); } @@ -537,6 +539,8 @@ namespace arith { euf::enode* n2 = var2enode(v2); lpvar w1 = register_theory_var_in_lar_solver(v1); lpvar w2 = register_theory_var_in_lar_solver(v2); + if (lp().are_equal(w1, w2)) + return; auto cs = lp().add_equality(w1, w2); add_eq_constraint(cs.first, n1, n2); add_eq_constraint(cs.second, n1, n2); From 7bbe3fb2b6e095bc15e5e23e4843049e7846b761 Mon Sep 17 00:00:00 2001 From: someplaceguy Date: Sat, 9 Mar 2024 23:13:42 +0000 Subject: [PATCH 63/69] fix (get-proof) command to respect option pp.simplify_implies (#7157) --- src/ast/ast_smt_pp.cpp | 10 +++++----- src/cmd_context/basic_cmds.cpp | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index bea669438..0da4f1c12 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -986,7 +986,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { ast_mark sort_mark; for (sort* s : decls.get_sorts()) { if (!(*m_is_declared)(s)) { - smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0); + smt_printer p(strm, m, ql, rn, m_logic, true, m_simplify_implies, 0); p.pp_sort_decl(sort_mark, s); } } @@ -994,7 +994,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { for (unsigned i = 0; i < decls.get_num_decls(); ++i) { func_decl* d = decls.get_func_decls()[i]; if (!(*m_is_declared)(d)) { - smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0); + smt_printer p(strm, m, ql, rn, m_logic, true, m_simplify_implies, 0); p(d); strm << "\n"; } @@ -1003,20 +1003,20 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { #endif for (expr* a : m_assumptions) { - smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1); + smt_printer p(strm, m, ql, rn, m_logic, false, m_simplify_implies, 1); strm << "(assert\n "; p(a); strm << ")\n"; } for (expr* a : m_assumptions_star) { - smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1); + smt_printer p(strm, m, ql, rn, m_logic, false, m_simplify_implies, 1); strm << "(assert\n "; p(a); strm << ")\n"; } - smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 0); + smt_printer p(strm, m, ql, rn, m_logic, false, m_simplify_implies, 0); if (m.is_bool(n)) { if (!m.is_true(n)) { strm << "(assert\n "; diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index a2757d955..c93e4432f 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -202,6 +202,7 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", { cmd_is_declared isd(ctx); pp.set_is_declared(&isd); pp.set_logic(ctx.get_logic()); + pp.set_simplify_implies(params.simplify_implies()); pp.display_smt2(ctx.regular_stream(), pr); ctx.regular_stream() << std::endl; } From 0b3bbc297248849cb17c29e0fbaa23f61bb45716 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Mar 2024 18:19:36 -0700 Subject: [PATCH 64/69] #7158 Signed-off-by: Nikolaj Bjorner --- src/api/api_util.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/api_util.h b/src/api/api_util.h index 0ff2c8ddd..174d75144 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -110,6 +110,7 @@ inline param_descrs * to_param_descrs_ptr(Z3_param_descrs p) { return p == nullp Z3_TRY; \ RESET_ERROR_CODE(); \ EXTRA_CODE; \ + CHECK_IS_EXPR(n, nullptr); \ expr * _n = to_expr(n); \ ast* a = mk_c(c)->m().mk_app(FID, OP, 0, 0, 1, &_n); \ mk_c(c)->save_ast_trail(a); \ @@ -127,6 +128,8 @@ Z3_ast Z3_API NAME(Z3_context c, Z3_ast n) { \ Z3_TRY; \ RESET_ERROR_CODE(); \ EXTRA_CODE; \ + CHECK_IS_EXPR(n1, nullptr); \ + CHECK_IS_EXPR(n2, nullptr); \ expr * args[2] = { to_expr(n1), to_expr(n2) }; \ ast* a = mk_c(c)->m().mk_app(FID, OP, 0, 0, 2, args); \ mk_c(c)->save_ast_trail(a); \ From 5704e8d15460236d09678b2f514023446445d510 Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Thu, 14 Mar 2024 16:48:38 +0100 Subject: [PATCH 65/69] fix intblast is_bounded (#7163) --- src/sat/smt/intblast_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index 2c373f6b9..f4491896b 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -467,7 +467,7 @@ namespace intblast { bool solver::is_bounded(expr* x, rational const& N) { return any_of(m_vars, [&](expr* v) { - return is_translated(v) && translated(v) == x && bv.get_bv_size(v) <= N; + return is_translated(v) && translated(v) == x && bv_size(v) <= N; }); } @@ -536,7 +536,7 @@ namespace intblast { * Perform simplifications that are claimed sound when the bit-vector interpretations of * mod/div always guard the mod and dividend to be non-zero. * Potentially shady area is for arithmetic expressions created by int2bv. - * They will be guarded by a modulus which dose not disappear. + * They will be guarded by a modulus which does not disappear. */ expr* solver::amod(expr* bv_expr, expr* x, rational const& N) { rational v; From 6450a7a0b847e1d6338c836e8b70dae2b916b30f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:54:01 -0700 Subject: [PATCH 66/69] Bump docker/build-push-action from 5.1.0 to 5.2.0 (#7159) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.1.0 to 5.2.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5.1.0...v5.2.0) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 5bb7d2cad..3122f6e70 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -41,7 +41,7 @@ jobs: type=edge type=sha,prefix=ubuntu-20.04-bare-z3-sha- - name: Build and push Bare Z3 Docker Image - uses: docker/build-push-action@v5.1.0 + uses: docker/build-push-action@v5.2.0 with: context: . push: true From b8a69987c31a74ac0a611b99ca97bb3edd28dc86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Mar 2024 16:33:32 -0700 Subject: [PATCH 67/69] fix #7165 --- src/api/python/z3/z3.py | 4 ++-- src/tactic/goal.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 16db39afd..9a3dadda2 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5445,10 +5445,10 @@ def EnumSort(name, values, ctx=None): num = len(values) _val_names = (Symbol * num)() for i in range(num): - _val_names[i] = to_symbol(values[i]) + _val_names[i] = to_symbol(values[i], ctx) _values = (FuncDecl * num)() _testers = (FuncDecl * num)() - name = to_symbol(name) + name = to_symbol(name, ctx) S = DatatypeSortRef(Z3_mk_enumeration_sort(ctx.ref(), name, num, _val_names, _values, _testers), ctx) V = [] for i in range(num): diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 23e3ff969..43cecf92d 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -696,7 +696,7 @@ bool goal::is_cnf() const { if (!is_literal(lit)) return false; } - if (!is_literal(f)) + else if (!is_literal(f)) return false; } return true; From 18365907a27e03a99092238646b1d7a65fc20ca3 Mon Sep 17 00:00:00 2001 From: cctv130 <133784576+cctv130@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:29:27 +0800 Subject: [PATCH 68/69] Update util.h (#7169) --- src/util/util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/util.h b/src/util/util.h index a4bf78073..f05e4f9f4 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -142,6 +142,7 @@ static inline unsigned get_num_1bits(uint64_t v) { v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F; uint64_t r = (v * 0x0101010101010101) >> 56; SASSERT(c == r); + return r; #endif } From 1a7437144c63a33cee9043c5bb370318836e329d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:25:58 -0700 Subject: [PATCH 69/69] Bump docker/build-push-action from 5.2.0 to 5.3.0 (#7170) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.2.0 to 5.3.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5.2.0...v5.3.0) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 3122f6e70..d93e7eeef 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -41,7 +41,7 @@ jobs: type=edge type=sha,prefix=ubuntu-20.04-bare-z3-sha- - name: Build and push Bare Z3 Docker Image - uses: docker/build-push-action@v5.2.0 + uses: docker/build-push-action@v5.3.0 with: context: . push: true