9
9
// except according to those terms.
10
10
11
11
use std:: cmp:: Ordering ;
12
- use std:: hash;
13
- use std:: mem:: transmute;
12
+ use std:: num:: ParseFloatError ;
13
+
14
+ use syntax:: ast;
15
+
16
+ use rustc_apfloat:: { Float , FloatConvert , Status } ;
17
+ use rustc_apfloat:: ieee:: { Single , Double } ;
14
18
15
19
use super :: err:: * ;
16
20
17
- #[ derive( Copy , Clone , Debug , RustcEncodable , RustcDecodable ) ]
18
- pub enum ConstFloat {
19
- F32 ( f32 ) ,
20
- F64 ( f64 )
21
+ // Note that equality for `ConstFloat` means that the it is the same
22
+ // constant, not that the rust values are equal. In particular, `NaN
23
+ // == NaN` (at least if it's the same NaN; distinct encodings for NaN
24
+ // are considering unequal).
25
+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , RustcEncodable , RustcDecodable ) ]
26
+ pub struct ConstFloat {
27
+ pub ty : ast:: FloatTy ,
28
+
29
+ // This is a bit inefficient but it makes conversions below more
30
+ // ergonomic, and all of this will go away once `miri` is merged.
31
+ pub bits : u128 ,
21
32
}
22
- pub use self :: ConstFloat :: * ;
23
33
24
34
impl ConstFloat {
25
35
/// Description of the type, not the value
26
36
pub fn description ( & self ) -> & ' static str {
27
- match * self {
28
- F32 ( _) => "f32" ,
29
- F64 ( _) => "f64" ,
30
- }
37
+ self . ty . ty_to_string ( )
31
38
}
32
39
33
40
pub fn is_nan ( & self ) -> bool {
34
- match * self {
35
- F32 ( f ) => f . is_nan ( ) ,
36
- F64 ( f ) => f . is_nan ( ) ,
41
+ match self . ty {
42
+ ast :: FloatTy :: F32 => Single :: from_bits ( self . bits ) . is_nan ( ) ,
43
+ ast :: FloatTy :: F64 => Double :: from_bits ( self . bits ) . is_nan ( ) ,
37
44
}
38
45
}
39
46
40
47
/// Compares the values if they are of the same type
41
48
pub fn try_cmp ( self , rhs : Self ) -> Result < Ordering , ConstMathErr > {
42
- match ( self , rhs) {
43
- ( F64 ( a) , F64 ( b) ) => {
49
+ match ( self . ty , rhs. ty ) {
50
+ ( ast:: FloatTy :: F64 , ast:: FloatTy :: F64 ) => {
51
+ let a = Double :: from_bits ( self . bits ) ;
52
+ let b = Double :: from_bits ( rhs. bits ) ;
44
53
// This is pretty bad but it is the existing behavior.
45
- Ok ( if a == b {
46
- Ordering :: Equal
47
- } else if a < b {
48
- Ordering :: Less
49
- } else {
50
- Ordering :: Greater
51
- } )
54
+ Ok ( a. partial_cmp ( & b) . unwrap_or ( Ordering :: Greater ) )
52
55
}
53
56
54
- ( F32 ( a) , F32 ( b) ) => {
55
- Ok ( if a == b {
56
- Ordering :: Equal
57
- } else if a < b {
58
- Ordering :: Less
59
- } else {
60
- Ordering :: Greater
61
- } )
57
+ ( ast:: FloatTy :: F32 , ast:: FloatTy :: F32 ) => {
58
+ let a = Single :: from_bits ( self . bits ) ;
59
+ let b = Single :: from_bits ( rhs. bits ) ;
60
+ Ok ( a. partial_cmp ( & b) . unwrap_or ( Ordering :: Greater ) )
62
61
}
63
62
64
63
_ => Err ( CmpBetweenUnequalTypes ) ,
65
64
}
66
65
}
67
- }
68
66
69
- /// Note that equality for `ConstFloat` means that the it is the same
70
- /// constant, not that the rust values are equal. In particular, `NaN
71
- /// == NaN` (at least if it's the same NaN; distinct encodings for NaN
72
- /// are considering unequal).
73
- impl PartialEq for ConstFloat {
74
- fn eq ( & self , other : & Self ) -> bool {
75
- match ( * self , * other) {
76
- ( F64 ( a) , F64 ( b) ) => {
77
- unsafe { transmute :: < _ , u64 > ( a) == transmute :: < _ , u64 > ( b) }
67
+ pub fn from_i128 ( input : i128 , ty : ast:: FloatTy ) -> Self {
68
+ let bits = match ty {
69
+ ast:: FloatTy :: F32 => Single :: from_i128 ( input) . value . to_bits ( ) ,
70
+ ast:: FloatTy :: F64 => Double :: from_i128 ( input) . value . to_bits ( )
71
+ } ;
72
+ ConstFloat { bits, ty }
73
+ }
74
+
75
+ pub fn from_u128 ( input : u128 , ty : ast:: FloatTy ) -> Self {
76
+ let bits = match ty {
77
+ ast:: FloatTy :: F32 => Single :: from_u128 ( input) . value . to_bits ( ) ,
78
+ ast:: FloatTy :: F64 => Double :: from_u128 ( input) . value . to_bits ( )
79
+ } ;
80
+ ConstFloat { bits, ty }
81
+ }
82
+
83
+ pub fn from_str ( num : & str , ty : ast:: FloatTy ) -> Result < Self , ParseFloatError > {
84
+ let bits = match ty {
85
+ ast:: FloatTy :: F32 => {
86
+ let rust_bits = num. parse :: < f32 > ( ) ?. to_bits ( ) as u128 ;
87
+ let apfloat = num. parse :: < Single > ( ) . unwrap_or_else ( |e| {
88
+ panic ! ( "apfloat::ieee::Single failed to parse `{}`: {:?}" , num, e) ;
89
+ } ) ;
90
+ let apfloat_bits = apfloat. to_bits ( ) ;
91
+ assert ! ( rust_bits == apfloat_bits,
92
+ "apfloat::ieee::Single gave different result for `{}`: \
93
+ {}({:#x}) vs Rust's {}({:#x})",
94
+ num, apfloat, apfloat_bits,
95
+ Single :: from_bits( rust_bits) , rust_bits) ;
96
+ apfloat_bits
78
97
}
79
- ( F32 ( a) , F32 ( b) ) => {
80
- unsafe { transmute :: < _ , u32 > ( a) == transmute :: < _ , u32 > ( b) }
98
+ ast:: FloatTy :: F64 => {
99
+ let rust_bits = num. parse :: < f64 > ( ) ?. to_bits ( ) as u128 ;
100
+ let apfloat = num. parse :: < Double > ( ) . unwrap_or_else ( |e| {
101
+ panic ! ( "apfloat::ieee::Double failed to parse `{}`: {:?}" , num, e) ;
102
+ } ) ;
103
+ let apfloat_bits = apfloat. to_bits ( ) ;
104
+ assert ! ( rust_bits == apfloat_bits,
105
+ "apfloat::ieee::Double gave different result for `{}`: \
106
+ {}({:#x}) vs Rust's {}({:#x})",
107
+ num, apfloat, apfloat_bits,
108
+ Double :: from_bits( rust_bits) , rust_bits) ;
109
+ apfloat_bits
81
110
}
82
- _ => false
111
+ } ;
112
+ Ok ( ConstFloat { bits, ty } )
113
+ }
114
+
115
+ pub fn to_i128 ( self , width : usize ) -> Option < i128 > {
116
+ assert ! ( width <= 128 ) ;
117
+ let r = match self . ty {
118
+ ast:: FloatTy :: F32 => Single :: from_bits ( self . bits ) . to_i128 ( width) ,
119
+ ast:: FloatTy :: F64 => Double :: from_bits ( self . bits ) . to_i128 ( width)
120
+ } ;
121
+ if r. status . intersects ( Status :: INVALID_OP ) {
122
+ None
123
+ } else {
124
+ Some ( r. value )
83
125
}
84
126
}
85
- }
86
127
87
- impl Eq for ConstFloat { }
128
+ pub fn to_u128 ( self , width : usize ) -> Option < u128 > {
129
+ assert ! ( width <= 128 ) ;
130
+ let r = match self . ty {
131
+ ast:: FloatTy :: F32 => Single :: from_bits ( self . bits ) . to_u128 ( width) ,
132
+ ast:: FloatTy :: F64 => Double :: from_bits ( self . bits ) . to_u128 ( width)
133
+ } ;
134
+ if r. status . intersects ( Status :: INVALID_OP ) {
135
+ None
136
+ } else {
137
+ Some ( r. value )
138
+ }
139
+ }
88
140
89
- impl hash:: Hash for ConstFloat {
90
- fn hash < H : hash:: Hasher > ( & self , state : & mut H ) {
91
- match * self {
92
- F64 ( a) => {
93
- unsafe { transmute :: < _ , u64 > ( a) } . hash ( state)
141
+ pub fn convert ( self , to : ast:: FloatTy ) -> Self {
142
+ let bits = match ( self . ty , to) {
143
+ ( ast:: FloatTy :: F32 , ast:: FloatTy :: F32 ) |
144
+ ( ast:: FloatTy :: F64 , ast:: FloatTy :: F64 ) => return self ,
145
+
146
+ ( ast:: FloatTy :: F32 , ast:: FloatTy :: F64 ) => {
147
+ Double :: to_bits ( Single :: from_bits ( self . bits ) . convert ( & mut false ) . value )
94
148
}
95
- F32 ( a ) => {
96
- unsafe { transmute :: < _ , u32 > ( a ) } . hash ( state )
149
+ ( ast :: FloatTy :: F64 , ast :: FloatTy :: F32 ) => {
150
+ Single :: to_bits ( Double :: from_bits ( self . bits ) . convert ( & mut false ) . value )
97
151
}
98
- }
152
+ } ;
153
+ ConstFloat { bits, ty : to }
99
154
}
100
155
}
101
156
102
157
impl :: std:: fmt:: Display for ConstFloat {
103
158
fn fmt ( & self , fmt : & mut :: std:: fmt:: Formatter ) -> Result < ( ) , :: std:: fmt:: Error > {
104
- match * self {
105
- F32 ( f ) => write ! ( fmt, "{}f32 " , f ) ,
106
- F64 ( f ) => write ! ( fmt, "{}f64 " , f ) ,
159
+ match self . ty {
160
+ ast :: FloatTy :: F32 => write ! ( fmt, "{:#} " , Single :: from_bits ( self . bits ) ) ? ,
161
+ ast :: FloatTy :: F64 => write ! ( fmt, "{:#} " , Double :: from_bits ( self . bits ) ) ? ,
107
162
}
163
+ write ! ( fmt, "{}" , self . ty)
164
+ }
165
+ }
166
+
167
+ impl :: std:: fmt:: Debug for ConstFloat {
168
+ fn fmt ( & self , fmt : & mut :: std:: fmt:: Formatter ) -> Result < ( ) , :: std:: fmt:: Error > {
169
+ :: std:: fmt:: Display :: fmt ( self , fmt)
108
170
}
109
171
}
110
172
@@ -113,11 +175,20 @@ macro_rules! derive_binop {
113
175
impl :: std:: ops:: $op for ConstFloat {
114
176
type Output = Result <Self , ConstMathErr >;
115
177
fn $func( self , rhs: Self ) -> Result <Self , ConstMathErr > {
116
- match ( self , rhs) {
117
- ( F32 ( a) , F32 ( b) ) => Ok ( F32 ( a. $func( b) ) ) ,
118
- ( F64 ( a) , F64 ( b) ) => Ok ( F64 ( a. $func( b) ) ) ,
119
- _ => Err ( UnequalTypes ( Op :: $op) ) ,
120
- }
178
+ let bits = match ( self . ty, rhs. ty) {
179
+ ( ast:: FloatTy :: F32 , ast:: FloatTy :: F32 ) =>{
180
+ let a = Single :: from_bits( self . bits) ;
181
+ let b = Single :: from_bits( rhs. bits) ;
182
+ a. $func( b) . value. to_bits( )
183
+ }
184
+ ( ast:: FloatTy :: F64 , ast:: FloatTy :: F64 ) => {
185
+ let a = Double :: from_bits( self . bits) ;
186
+ let b = Double :: from_bits( rhs. bits) ;
187
+ a. $func( b) . value. to_bits( )
188
+ }
189
+ _ => return Err ( UnequalTypes ( Op :: $op) ) ,
190
+ } ;
191
+ Ok ( ConstFloat { bits, ty: self . ty } )
121
192
}
122
193
}
123
194
}
@@ -132,9 +203,10 @@ derive_binop!(Rem, rem);
132
203
impl :: std:: ops:: Neg for ConstFloat {
133
204
type Output = Self ;
134
205
fn neg ( self ) -> Self {
135
- match self {
136
- F32 ( f) => F32 ( -f) ,
137
- F64 ( f) => F64 ( -f) ,
138
- }
206
+ let bits = match self . ty {
207
+ ast:: FloatTy :: F32 => ( -Single :: from_bits ( self . bits ) ) . to_bits ( ) ,
208
+ ast:: FloatTy :: F64 => ( -Double :: from_bits ( self . bits ) ) . to_bits ( ) ,
209
+ } ;
210
+ ConstFloat { bits, ty : self . ty }
139
211
}
140
212
}
0 commit comments