let reduce_by_cond ~with_alarms state cond =
if hasAttribute "volatile" (typeAttr (typeOf cond.exp)) then state
else
let rec aux cond state =
match cond.positive,cond.exp.enode with
| _positive, BinOp ((Le|Ne|Eq|Gt|Lt|Ge as binop), exp1, exp2, _typ) ->
let eval = eval_from_type (unrollType (typeOf exp1))
(Value_parameters.AllRoundingModes.get ())
in
reduce_by_comparison ~with_alarms eval
cond.positive exp1 binop exp2 state
| true, BinOp (LAnd, exp1, exp2, _)
| false, BinOp (LOr, exp1, exp2, _) ->
let new_state = aux {cond with exp = exp1} state in
let result = aux {cond with exp = exp2} new_state in
result
| false, BinOp (LAnd, exp1, exp2, _)
| true, BinOp (LOr, exp1, exp2, _) ->
let new_v1 = try aux {cond with exp = exp1} state
with Reduce_to_bottom -> Cvalue.Model.bottom
in let new_v2 = try aux {cond with exp = exp2} state
with Reduce_to_bottom -> Cvalue.Model.bottom
in let r = Cvalue.Model.join new_v1 new_v2 in
if Db.Value.is_reachable r then r else raise Reduce_to_bottom
| _, UnOp(LNot,exp,_) ->
aux { positive = not cond.positive; exp = exp; } state
| _, Lval _ when (let t = typeOf cond.exp in
isIntegralType t || isPointerType t)
->
(try
let loc,value_for_loc,_ =
eval_as_exact_loc ~with_alarms state cond.exp in
let new_value = eval_symetric_int
(not cond.positive) Eq V.singleton_zero value_for_loc
in
if V.equal new_value V.bottom then raise Reduce_to_bottom
else
Cvalue.Model.reduce_binding
~with_alarms:CilE.warn_none_mode state loc new_value
with Not_an_exact_loc -> state)
| _ -> state
in
let result = aux cond state in
let contains_zero =
if Value_parameters.UndefinedPointerComparisonPropagateAll.get()
then V.contains_zero
else (fun x -> V.is_included V.singleton_zero x)
in
let condition_may_still_be_true_in_state state =
let cond_interp = eval_expr ~with_alarms state cond.exp in
(not cond.positive || V.contains_non_zero cond_interp) &&
(cond.positive || contains_zero cond_interp)
in
if (not (Cvalue.Model.equal result state)) &&
(not (condition_may_still_be_true_in_state result))
then raise Reduce_to_bottom;
let is_enumerable v =
let v_interp =
Cvalue.Model.find ~conflate_bottom:true ~with_alarms result v
in
ignore (Location_Bytes.cardinal_less_than v_interp 7);
v_interp
in
let rec enumerate_one_var l =
match l with
| [] -> raise Not_found
| v::t ->
try
let v_interp = is_enumerable v in
v,v_interp,t
with Abstract_interp.Not_less_than ->
enumerate_one_var t
in
let invert_cond vl =
try
let v1,v_interp1, _tail = enumerate_one_var vl in
let f one_val acc =
let env =
Cvalue.Model.reduce_binding
~with_alarms:CilE.warn_none_mode
result v1 one_val
in
let stays = condition_may_still_be_true_in_state env in
if stays
then begin
Location_Bytes.join one_val acc
end
else begin
acc
end
in
let new_v_interp =
Location_Bytes.fold_enum
~split_non_enumerable:2
f v_interp1 Location_Bytes.bottom
in
let state_value =
if V.equal new_v_interp V.bottom
then raise Reduce_to_bottom
else
Cvalue.Model.reduce_binding
~with_alarms:CilE.warn_none_mode
result v1 new_v_interp
in
state_value
with Not_found -> result
in
let result =
invert_cond (get_influential_vars ~with_alarms result cond.exp)
in
if not (Cvalue.Model.is_reachable result)
then raise Reduce_to_bottom
else result