99// except according to those terms.
1010
1111use 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 } ;
1418
1519use super :: err:: * ;
1620
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 ,
2132}
22- pub use self :: ConstFloat :: * ;
2333
2434impl ConstFloat {
2535 /// Description of the type, not the value
2636 pub fn description ( & self ) -> & ' static str {
27- match * self {
28- F32 ( _) => "f32" ,
29- F64 ( _) => "f64" ,
30- }
37+ self . ty . ty_to_string ( )
3138 }
3239
3340 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 ( ) ,
3744 }
3845 }
3946
4047 /// Compares the values if they are of the same type
4148 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 ) ;
4453 // 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 ) )
5255 }
5356
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 ) )
6261 }
6362
6463 _ => Err ( CmpBetweenUnequalTypes ) ,
6564 }
6665 }
67- }
6866
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
7897 }
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
81110 }
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 )
83125 }
84126 }
85- }
86127
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+ }
88140
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 )
94148 }
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 )
97151 }
98- }
152+ } ;
153+ ConstFloat { bits, ty : to }
99154 }
100155}
101156
102157impl :: std:: fmt:: Display for ConstFloat {
103158 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 ) ) ? ,
107162 }
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)
108170 }
109171}
110172
@@ -113,11 +175,20 @@ macro_rules! derive_binop {
113175 impl :: std:: ops:: $op for ConstFloat {
114176 type Output = Result <Self , ConstMathErr >;
115177 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 } )
121192 }
122193 }
123194 }
@@ -132,9 +203,10 @@ derive_binop!(Rem, rem);
132203impl :: std:: ops:: Neg for ConstFloat {
133204 type Output = Self ;
134205 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 }
139211 }
140212}
0 commit comments