From aace07d3449b1d4eccc82b7a9bec8b8f507dc32b Mon Sep 17 00:00:00 2001 From: Virgile Prevosto <virgile.prevosto@m4x.org> Date: Fri, 28 Feb 2020 11:00:40 +0100 Subject: [PATCH] [kernel] interpret floating-point operations in constFold --- src/kernel_services/ast_queries/cil.ml | 60 +++++++++++++++++++ tests/syntax/compile_constant.c | 2 + .../syntax/oracle/compile_constant.res.oracle | 4 ++ 3 files changed, 66 insertions(+) create mode 100644 tests/syntax/compile_constant.c create mode 100644 tests/syntax/oracle/compile_constant.res.oracle diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml index b07aa521d24..6db513bc25a 100644 --- a/src/kernel_services/ast_queries/cil.ml +++ b/src/kernel_services/ast_queries/cil.ml @@ -3509,6 +3509,11 @@ let isArithmeticType t = (TInt _ | TEnum _ | TFloat _) -> true | _ -> false +let isLongDoubleType t = + match unrollTypeSkel t with + | TFloat(FLongDouble,_) -> true + | _ -> false + let isArithmeticOrPointerType t= match unrollTypeSkel t with | TInt _ | TEnum _ | TFloat _ | TPtr _ -> true @@ -4494,6 +4499,20 @@ and constFold (machdep: bool) (e: exp) : exp = with Floating_point.Float_Non_representable_as_Int64 _ -> (* too big*) new_exp ~loc (CastE (t, e)) end + | Const (CReal(f,_,_)), TFloat (FFloat,a) when a = [] -> + let f = Floating_point.round_to_single_precision_float f in + new_exp ~loc (Const (CReal (f,FFloat,None))) + | Const (CReal(f,_,_)), TFloat (FDouble,a) when a = [] -> + new_exp ~loc (Const (CReal (f,FDouble,None))) + (* We don't treat cast to long double, as we don't really know + how to handle this type anyway. *) + | Const (CInt64(i,_,_)), (TFloat(FFloat,a)) when a = [] -> + let f = Integer.to_float i in + let f = Floating_point.round_to_single_precision_float f in + new_exp ~loc (Const (CReal (f,FFloat,None))) + | Const (CInt64(i,_,_)), (TFloat(FDouble,a)) when a = [] -> + let f = Integer.to_float i in + new_exp ~loc (Const (CReal (f,FDouble,None))) | _, _ -> new_exp ~loc (CastE (t, e)) end | Lval lv -> new_exp ~loc (Lval (constFoldLval machdep lv)) @@ -4651,6 +4670,18 @@ and constFoldBinOp ~loc (machdep: bool) bop e1 e2 tres = | Gt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) -> let i1', i2', _ = convertInts i1 ik1 i2 ik2 in if Integer.gt i1' i2' then one ~loc else zero ~loc + | Eq, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + if f1 = f2 then one ~loc else zero ~loc + | Ne, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + if f1 = f2 then zero ~loc else one ~loc + | Le, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + if f1 <= f2 then one ~loc else zero ~loc + | Ge, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + if f1 >= f2 then one ~loc else zero ~loc + | Lt, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + if f1 < f2 then one ~loc else zero ~loc + | Gt, Const(CReal(f1,fk1,_)),Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + if f1 > f2 then one ~loc else zero ~loc (* We rely on the fact that LAnd/LOr appear in global initializers and should not have side effects. *) @@ -4669,6 +4700,35 @@ and constFoldBinOp ~loc (machdep: bool) bop e1 e2 tres = !pp_exp_ref (new_exp ~loc (BinOp(bop, e1', e2', tres))) !pp_exp_ref newe; newe + end else if isArithmeticType tres && not (isLongDoubleType tres) then begin + let tk = + match unrollTypeSkel tres with + | TFloat(fk,_) -> fk + | _ -> Kernel.fatal "constFoldBinOp: not a floating type" + in + let is_single_precision = + match tk with + | FFloat -> true + | FDouble | FLongDouble -> false + in + let mkFloat f = + let f = + if is_single_precision then + Floating_point.round_to_single_precision_float f + else f + in + new_exp ~loc (Const (CReal(f,tk,None))) + in + match bop, e1'.enode, e2'.enode with + | PlusA, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + mkFloat (f1 +. f2) + | MinusA, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + mkFloat (f1 -. f2) + | Mult, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + mkFloat (f1 *. f2) + | Div, Const(CReal(f1,fk1,_)), Const(CReal(f2,fk2,_)) when fk1 = fk2 -> + mkFloat (f1 /. f2) (*might be infinity or NaN, but that's still a float*) + | _ -> new_exp ~loc (BinOp(bop,e1',e2',tres)) end else new_exp ~loc (BinOp(bop, e1', e2', tres)) diff --git a/tests/syntax/compile_constant.c b/tests/syntax/compile_constant.c new file mode 100644 index 00000000000..dc2acdcdd52 --- /dev/null +++ b/tests/syntax/compile_constant.c @@ -0,0 +1,2 @@ +#define M0(x) (x)*(x)<4.0?0.0:1.0 +char pixels[] = {M0(0.0), M0(1), M0(2.0f)}; diff --git a/tests/syntax/oracle/compile_constant.res.oracle b/tests/syntax/oracle/compile_constant.res.oracle new file mode 100644 index 00000000000..d5b6a340f31 --- /dev/null +++ b/tests/syntax/oracle/compile_constant.res.oracle @@ -0,0 +1,4 @@ +[kernel] Parsing tests/syntax/compile_constant.c (with preprocessing) +/* Generated by Frama-C */ +char pixels[3] = {(char)0.0, (char)0.0, (char)1.0}; + -- GitLab