-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathconvert_float_literal.cpp
103 lines (83 loc) · 2.9 KB
/
convert_float_literal.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*******************************************************************\
Module: C++ Language Conversion
Author: Daniel Kroening, [email protected]
\*******************************************************************/
/// \file
/// C++ Language Conversion
#include "convert_float_literal.h"
#include <util/c_types.h>
#include <util/config.h>
#include <util/ieee_float.h>
#include <util/std_expr.h>
#include <ansi-c/gcc_types.h>
#include "parse_float.h"
/// build an expression from a floating-point literal
/// \return either a constant_exprt or a complex_exprt
exprt convert_float_literal(const std::string &src)
{
parse_floatt parsed_float(src);
// In ANSI-C, float literals are double by default,
// unless marked with 'f' (this can be overridden with
// config.ansi_c.single_precision_constant).
// Furthermore, floating-point literals can be complex.
floatbv_typet type;
if(parsed_float.is_float)
type = float_type();
else if(parsed_float.is_long)
type = long_double_type();
else if(parsed_float.is_float16)
type = gcc_float16_type();
else if(parsed_float.is_float32)
type = gcc_float32_type();
else if(parsed_float.is_float32x)
type = gcc_float32x_type();
else if(parsed_float.is_float64)
type = gcc_float64_type();
else if(parsed_float.is_float64x)
type = gcc_float64x_type();
else if(parsed_float.is_float80)
{
type = ieee_float_spect(64, 15).to_type();
type.set(ID_C_c_type, ID_long_double);
}
else if(parsed_float.is_float128)
type = gcc_float128_type();
else if(parsed_float.is_float128x)
type = gcc_float128x_type();
else
{
// default
if(config.ansi_c.single_precision_constant)
type = float_type(); // default
else
type = double_type(); // default
}
if(parsed_float.is_decimal)
{
// TODO - should set ID_gcc_decimal32/ID_gcc_decimal64/ID_gcc_decimal128,
// but these aren't handled anywhere
}
// Compile-time rounding is implementation defined.
// The choice below is arbitrary.
ieee_floatt a(type, ieee_floatt::rounding_modet::ROUND_TO_EVEN);
if(parsed_float.exponent_base==10)
a.from_base10(parsed_float.significand, parsed_float.exponent);
else if(parsed_float.exponent_base==2) // hex
a.build(parsed_float.significand, parsed_float.exponent);
else
UNREACHABLE;
constant_exprt result = a.to_expr();
// ieee_floatt::to_expr gives us the representation, but doesn't preserve the
// distinction between bitwise-identical types such as _Float32 vs. float,
// so ensure we preserve that here:
result.type() = type;
if(parsed_float.is_imaginary)
{
const complex_typet complex_type(type);
constant_exprt zero_real_component = ieee_floatt::zero(type).to_expr();
// As above, ensure we preserve the exact type of the literal:
zero_real_component.type() = type;
return complex_exprt(zero_real_component, result, complex_type);
}
return std::move(result);
}