@@ -268,44 +268,55 @@ module CilOfApron (V: SV) =
268268struct
269269 exception Unsupported_Linexpr1
270270
271+ let longlong = TInt (ILongLong ,[] )
272+
273+
274+ (* * Returned boolean indicates whether returned expression should be negated. *)
275+ let coeff_to_const ~scalewith (c :Coeff.union_5 ) =
276+ match c with
277+ | Scalar c ->
278+ (match int_of_scalar ?scalewith c with
279+ | Some i ->
280+ let ci,truncation = truncateCilint ILongLong i in
281+ if truncation = NoTruncation then
282+ if Z. compare i Z. zero > = 0 then
283+ false , Const (CInt (i,ILongLong ,None ))
284+ else
285+ (* attempt to negate if that does not cause an overflow *)
286+ let cneg, truncation = truncateCilint ILongLong (Z. neg i) in
287+ if truncation = NoTruncation then
288+ true , Const (CInt ((Z. neg i),ILongLong ,None ))
289+ else
290+ false , Const (CInt (i,ILongLong ,None ))
291+ else
292+ (M. warn ~category: Analyzer " Invariant Apron: coefficient is not int: %a" Scalar. pretty c; raise Unsupported_Linexpr1 )
293+ | None -> raise Unsupported_Linexpr1 )
294+ | _ -> raise Unsupported_Linexpr1
295+
296+ (* * Returned boolean indicates whether returned expression should be negated. *)
297+ let cil_exp_of_linexpr1_term ~scalewith (c : Coeff.t ) v =
298+ match V. to_cil_varinfo v with
299+ | Some vinfo when IntDomain.Size. is_cast_injective ~from_type: vinfo.vtype ~to_type: (TInt (ILongLong ,[] )) ->
300+ let var = Cilfacade. mkCast ~e: (Lval (Var vinfo,NoOffset )) ~newt: longlong in
301+ let flip, coeff = coeff_to_const ~scalewith c in
302+ let prod = BinOp (Mult , coeff, var, longlong) in
303+ flip, prod
304+ | None ->
305+ M. warn ~category: Analyzer " Invariant Apron: cannot convert to cil var: %a" Var. pretty v;
306+ raise Unsupported_Linexpr1
307+ | _ ->
308+ M. warn ~category: Analyzer " Invariant Apron: cannot convert to cil var in overflow preserving manner: %a" Var. pretty v;
309+ raise Unsupported_Linexpr1
310+
311+ (* * Returned booleans indicates whether returned expressions should be negated. *)
271312 let cil_exp_of_linexpr1 ?scalewith (linexpr1 :Linexpr1.t ) =
272- let longlong = TInt (ILongLong ,[] ) in
273- let coeff_to_const consider_flip (c :Coeff.union_5 ) = match c with
274- | Scalar c ->
275- (match int_of_scalar ?scalewith c with
276- | Some i ->
277- let ci,truncation = truncateCilint ILongLong i in
278- if truncation = NoTruncation then
279- if not consider_flip || Z. compare i Z. zero > = 0 then
280- Const (CInt (i,ILongLong ,None )), false
281- else
282- (* attempt to negate if that does not cause an overflow *)
283- let cneg, truncation = truncateCilint ILongLong (Z. neg i) in
284- if truncation = NoTruncation then
285- Const (CInt ((Z. neg i),ILongLong ,None )), true
286- else
287- Const (CInt (i,ILongLong ,None )), false
288- else
289- (M. warn ~category: Analyzer " Invariant Apron: coefficient is not int: %a" Scalar. pretty c; raise Unsupported_Linexpr1 )
290- | None -> raise Unsupported_Linexpr1 )
291- | _ -> raise Unsupported_Linexpr1
292- in
293- let expr = ref (fst @@ coeff_to_const false (Linexpr1. get_cst linexpr1)) in
313+ let terms = ref [coeff_to_const ~scalewith (Linexpr1. get_cst linexpr1)] in
294314 let append_summand (c :Coeff.union_5 ) v =
295- match V. to_cil_varinfo v with
296- | Some vinfo when IntDomain.Size. is_cast_injective ~from_type: vinfo.vtype ~to_type: (TInt (ILongLong ,[] )) ->
297- let var = Cilfacade. mkCast ~e: (Lval (Var vinfo,NoOffset )) ~newt: longlong in
298- let coeff, flip = coeff_to_const true c in
299- let prod = BinOp (Mult , coeff, var, longlong) in
300- if flip then
301- expr := BinOp (MinusA ,! expr,prod,longlong)
302- else
303- expr := BinOp (PlusA ,! expr,prod,longlong)
304- | None -> M. warn ~category: Analyzer " Invariant Apron: cannot convert to cil var: %a" Var. pretty v; raise Unsupported_Linexpr1
305- | _ -> M. warn ~category: Analyzer " Invariant Apron: cannot convert to cil var in overflow preserving manner: %a" Var. pretty v; raise Unsupported_Linexpr1
315+ if not (Coeff. is_zero c) then
316+ terms := cil_exp_of_linexpr1_term ~scalewith c v :: ! terms
306317 in
307318 Linexpr1. iter append_summand linexpr1;
308- ! expr
319+ ! terms
309320
310321
311322 let lcm_den linexpr1 =
@@ -339,13 +350,27 @@ struct
339350 try
340351 let linexpr1 = Lincons1. get_linexpr1 lincons1 in
341352 let common_denominator = lcm_den linexpr1 in
342- let cilexp = cil_exp_of_linexpr1 ~scalewith: common_denominator linexpr1 in
343- match Lincons1. get_typ lincons1 with
344- | EQ -> Some (Cil. constFold false @@ BinOp (Eq , cilexp, zero, TInt (IInt ,[] )))
345- | SUPEQ -> Some (Cil. constFold false @@ BinOp (Ge , cilexp, zero, TInt (IInt ,[] )))
346- | SUP -> Some (Cil. constFold false @@ BinOp (Gt , cilexp, zero, TInt (IInt ,[] )))
347- | DISEQ -> Some (Cil. constFold false @@ BinOp (Ne , cilexp, zero, TInt (IInt ,[] )))
348- | EQMOD _ -> None
353+ let terms = cil_exp_of_linexpr1 ~scalewith: common_denominator linexpr1 in
354+ let (nterms, pterms) = Tuple2. mapn (List. map snd) (List. partition fst terms) in (* partition terms into negative (nterms) and positive (pterms) *)
355+ let fold_terms terms =
356+ List. fold_left (fun acc term ->
357+ match acc with
358+ | None -> Some term
359+ | Some exp -> Some (BinOp (PlusA , exp, term, longlong))
360+ ) None terms
361+ |> Option. default zero
362+ in
363+ let lhs = fold_terms pterms in
364+ let rhs = fold_terms nterms in (* negative terms are moved from Apron's lhs to our rhs, so they all become positive there *)
365+ let binop =
366+ match Lincons1. get_typ lincons1 with
367+ | EQ -> Eq
368+ | SUPEQ -> Ge
369+ | SUP -> Gt
370+ | DISEQ -> Ne
371+ | EQMOD _ -> raise Unsupported_Linexpr1
372+ in
373+ Some (Cil. constFold false @@ BinOp (binop, lhs, rhs, TInt (IInt ,[] ))) (* constFold removes multiplication by factor 1 *)
349374 with
350375 Unsupported_Linexpr1 -> None
351376end
0 commit comments