diff --git a/cranelift/docs/cton_lexer.py b/cranelift/docs/cton_lexer.py index 868bb23241..b40cb70e41 100644 --- a/cranelift/docs/cton_lexer.py +++ b/cranelift/docs/cton_lexer.py @@ -39,7 +39,7 @@ class CretonneLexer(RegexLexer): # Numbers. (r'[-+]?0[xX][0-9a-fA-F]+', Number.Hex), (r'[-+]?0[xX][0-9a-fA-F]*\.[0-9a-fA-F]*([pP]\d+)?', Number.Hex), - (r'[-+]?(\d+\.\d+([eE]\d+)?|[sq]NaN|Inf)', Number.Float), + (r'[-+]?(\d+\.\d+([eE]\d+)?|s?NaN|Inf)', Number.Float), (r'[-+]?\d+', Number.Integer), # Known attributes. (keywords('align', 'aligntrap', 'uext', 'sext', 'inreg'), diff --git a/cranelift/docs/example.cton b/cranelift/docs/example.cton index cdfc61bf4b..db87e891d1 100644 --- a/cranelift/docs/example.cton +++ b/cranelift/docs/example.cton @@ -1,18 +1,20 @@ +test verifier + function average(i32, i32) -> f32 { - ss1 = stack_slot 8, align 4 ; Stack slot for ``sum``. + ss1 = stack_slot 8 ; Stack slot for ``sum``. ebb1(v1: i32, v2: i32): v3 = f64const 0x0.0 stack_store v3, ss1 brz v2, ebb3 ; Handle count == 0. v4 = iconst.i32 0 - br ebb2(v4) + jump ebb2(v4) ebb2(v5: i32): v6 = imul_imm v5, 4 v7 = iadd v1, v6 v8 = heap_load.f32 v7 ; array[i] - v9 = fext.f64 v8 + v9 = fpromote.f64 v8 v10 = stack_load.f64 ss1 v11 = fadd v9, v10 stack_store v11, ss1 @@ -20,12 +22,12 @@ ebb2(v5: i32): v13 = icmp ult v12, v2 brnz v13, ebb2(v12) ; Loop backedge. v14 = stack_load.f64 ss1 - v15 = cvt_utof.f64 v2 + v15 = fcvt_from_uint.f64 v2 v16 = fdiv v14, v15 - v17 = ftrunc.f32 v16 + v17 = fdemote.f32 v16 return v17 ebb3: - v100 = f32const qNaN + v100 = f32const +NaN return v100 } diff --git a/cranelift/docs/langref.rst b/cranelift/docs/langref.rst index 4156a95aa3..6ded3a8bfd 100644 --- a/cranelift/docs/langref.rst +++ b/cranelift/docs/langref.rst @@ -31,8 +31,7 @@ Here is the same function compiled into Cretonne IL: .. literalinclude:: example.cton :language: cton - :linenos: - :emphasize-lines: 2 + :lines: 2- The first line of a function definition provides the function *name* and the :term:`function signature` which declares the argument and return types. diff --git a/cranelift/test-all.sh b/cranelift/test-all.sh index 522cf594a2..5b718d8bc4 100755 --- a/cranelift/test-all.sh +++ b/cranelift/test-all.sh @@ -79,6 +79,6 @@ export CTONUTIL="$topdir/target/release/cton-util" cd "$topdir" banner "File tests" -"$CTONUTIL" test filetests +"$CTONUTIL" test filetests docs banner "OK" diff --git a/lib/cretonne/src/ir/immediates.rs b/lib/cretonne/src/ir/immediates.rs index 120409f3b8..e061b88482 100644 --- a/lib/cretonne/src/ir/immediates.rs +++ b/lib/cretonne/src/ir/immediates.rs @@ -337,6 +337,11 @@ fn format_float(bits: u64, w: u8, t: u8, f: &mut Formatter) -> fmt::Result { write!(f, "0x0.{0:01$x}p{2}", left_t_bits, digits as usize, emin) } } else if e_bits == max_e_bits { + // Always print a `+` or `-` sign for these special values. + // This makes them easier to parse as they can't be confused as identifiers. + if sign_bit == 0 { + write!(f, "+")?; + } if t_bits == 0 { // Infinity. write!(f, "Inf") @@ -375,6 +380,8 @@ fn parse_float(s: &str, w: u8, t: u8) -> Result { let (sign_bit, s2) = if s.starts_with('-') { (1u64 << t + w, &s[1..]) + } else if s.starts_with('+') { + (0, &s[1..]) } else { (0, s) }; @@ -731,27 +738,29 @@ mod tests { "0x0.800000p-126"); assert_eq!(Ieee32::new(f32::MIN_POSITIVE * f32::EPSILON).to_string(), "0x0.000002p-126"); - assert_eq!(Ieee32::new(f32::INFINITY).to_string(), "Inf"); + assert_eq!(Ieee32::new(f32::INFINITY).to_string(), "+Inf"); assert_eq!(Ieee32::new(f32::NEG_INFINITY).to_string(), "-Inf"); - assert_eq!(Ieee32::new(f32::NAN).to_string(), "NaN"); + assert_eq!(Ieee32::new(f32::NAN).to_string(), "+NaN"); assert_eq!(Ieee32::new(-f32::NAN).to_string(), "-NaN"); // Construct some qNaNs with payloads. - assert_eq!(Ieee32::from_bits(0x7fc00001).to_string(), "NaN:0x1"); - assert_eq!(Ieee32::from_bits(0x7ff00001).to_string(), "NaN:0x300001"); + assert_eq!(Ieee32::from_bits(0x7fc00001).to_string(), "+NaN:0x1"); + assert_eq!(Ieee32::from_bits(0x7ff00001).to_string(), "+NaN:0x300001"); // Signaling NaNs. - assert_eq!(Ieee32::from_bits(0x7f800001).to_string(), "sNaN:0x1"); - assert_eq!(Ieee32::from_bits(0x7fa00001).to_string(), "sNaN:0x200001"); + assert_eq!(Ieee32::from_bits(0x7f800001).to_string(), "+sNaN:0x1"); + assert_eq!(Ieee32::from_bits(0x7fa00001).to_string(), "+sNaN:0x200001"); } #[test] fn parse_ieee32() { parse_ok::("0.0", "0.0"); + parse_ok::("+0.0", "0.0"); parse_ok::("-0.0", "-0.0"); parse_ok::("0x0", "0.0"); parse_ok::("0x0.0", "0.0"); parse_ok::("0x.0", "0.0"); parse_ok::("0x0.", "0.0"); parse_ok::("0x1", "0x1.000000p0"); + parse_ok::("+0x1", "0x1.000000p0"); parse_ok::("-0x1", "-0x1.000000p0"); parse_ok::("0x10", "0x1.000000p4"); parse_ok::("0x10.0", "0x1.000000p4"); @@ -793,20 +802,22 @@ mod tests { parse_err::("0x1.0p-150", "Magnitude too small"); // NaNs and Infs. - parse_ok::("Inf", "Inf"); + parse_ok::("Inf", "+Inf"); + parse_ok::("+Inf", "+Inf"); parse_ok::("-Inf", "-Inf"); - parse_ok::("NaN", "NaN"); + parse_ok::("NaN", "+NaN"); + parse_ok::("+NaN", "+NaN"); parse_ok::("-NaN", "-NaN"); - parse_ok::("NaN:0x0", "NaN"); + parse_ok::("NaN:0x0", "+NaN"); parse_err::("NaN:", "Float must be hexadecimal"); parse_err::("NaN:0", "Float must be hexadecimal"); parse_err::("NaN:0x", "Invalid NaN payload"); - parse_ok::("NaN:0x000001", "NaN:0x1"); - parse_ok::("NaN:0x300001", "NaN:0x300001"); + parse_ok::("NaN:0x000001", "+NaN:0x1"); + parse_ok::("NaN:0x300001", "+NaN:0x300001"); parse_err::("NaN:0x400001", "Invalid NaN payload"); - parse_ok::("sNaN:0x1", "sNaN:0x1"); + parse_ok::("sNaN:0x1", "+sNaN:0x1"); parse_err::("sNaN:0x0", "Invalid sNaN payload"); - parse_ok::("sNaN:0x200001", "sNaN:0x200001"); + parse_ok::("sNaN:0x200001", "+sNaN:0x200001"); parse_err::("sNaN:0x400001", "Invalid sNaN payload"); } @@ -829,19 +840,20 @@ mod tests { "0x0.8000000000000p-1022"); assert_eq!(Ieee64::new(f64::MIN_POSITIVE * f64::EPSILON).to_string(), "0x0.0000000000001p-1022"); - assert_eq!(Ieee64::new(f64::INFINITY).to_string(), "Inf"); + assert_eq!(Ieee64::new(f64::INFINITY).to_string(), "+Inf"); assert_eq!(Ieee64::new(f64::NEG_INFINITY).to_string(), "-Inf"); - assert_eq!(Ieee64::new(f64::NAN).to_string(), "NaN"); + assert_eq!(Ieee64::new(f64::NAN).to_string(), "+NaN"); assert_eq!(Ieee64::new(-f64::NAN).to_string(), "-NaN"); // Construct some qNaNs with payloads. - assert_eq!(Ieee64::from_bits(0x7ff8000000000001).to_string(), "NaN:0x1"); + assert_eq!(Ieee64::from_bits(0x7ff8000000000001).to_string(), + "+NaN:0x1"); assert_eq!(Ieee64::from_bits(0x7ffc000000000001).to_string(), - "NaN:0x4000000000001"); + "+NaN:0x4000000000001"); // Signaling NaNs. assert_eq!(Ieee64::from_bits(0x7ff0000000000001).to_string(), - "sNaN:0x1"); + "+sNaN:0x1"); assert_eq!(Ieee64::from_bits(0x7ff4000000000001).to_string(), - "sNaN:0x4000000000001"); + "+sNaN:0x4000000000001"); } #[test] @@ -894,20 +906,20 @@ mod tests { parse_err::("0x1.0p-1075", "Magnitude too small"); // NaNs and Infs. - parse_ok::("Inf", "Inf"); + parse_ok::("Inf", "+Inf"); parse_ok::("-Inf", "-Inf"); - parse_ok::("NaN", "NaN"); + parse_ok::("NaN", "+NaN"); parse_ok::("-NaN", "-NaN"); - parse_ok::("NaN:0x0", "NaN"); + parse_ok::("NaN:0x0", "+NaN"); parse_err::("NaN:", "Float must be hexadecimal"); parse_err::("NaN:0", "Float must be hexadecimal"); parse_err::("NaN:0x", "Invalid NaN payload"); - parse_ok::("NaN:0x000001", "NaN:0x1"); - parse_ok::("NaN:0x4000000000001", "NaN:0x4000000000001"); + parse_ok::("NaN:0x000001", "+NaN:0x1"); + parse_ok::("NaN:0x4000000000001", "+NaN:0x4000000000001"); parse_err::("NaN:0x8000000000001", "Invalid NaN payload"); - parse_ok::("sNaN:0x1", "sNaN:0x1"); + parse_ok::("sNaN:0x1", "+sNaN:0x1"); parse_err::("sNaN:0x0", "Invalid sNaN payload"); - parse_ok::("sNaN:0x4000000000001", "sNaN:0x4000000000001"); + parse_ok::("sNaN:0x4000000000001", "+sNaN:0x4000000000001"); parse_err::("sNaN:0x8000000000001", "Invalid sNaN payload"); } }