Browse Source

Ensure that the docs examples verify as Cretonne IL.

Any *.cton files in the docs directory are now included when running the
test-all.sh script. This is to ensure that the examples are in fact
correct IL.

Always print NaN and Inf floats with a sign. Print the positive ones as
+NaN and +Inf to make them easier to parse.
pull/3/head
Jakob Stoklund Olesen 8 years ago
parent
commit
46f0393417
  1. 2
      docs/cton_lexer.py
  2. 14
      docs/example.cton
  3. 3
      docs/langref.rst
  4. 64
      lib/cretonne/src/ir/immediates.rs
  5. 2
      test-all.sh

2
docs/cton_lexer.py

@ -39,7 +39,7 @@ class CretonneLexer(RegexLexer):
# Numbers. # Numbers.
(r'[-+]?0[xX][0-9a-fA-F]+', Number.Hex), (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'[-+]?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), (r'[-+]?\d+', Number.Integer),
# Known attributes. # Known attributes.
(keywords('align', 'aligntrap', 'uext', 'sext', 'inreg'), (keywords('align', 'aligntrap', 'uext', 'sext', 'inreg'),

14
docs/example.cton

@ -1,18 +1,20 @@
test verifier
function average(i32, i32) -> f32 { 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): ebb1(v1: i32, v2: i32):
v3 = f64const 0x0.0 v3 = f64const 0x0.0
stack_store v3, ss1 stack_store v3, ss1
brz v2, ebb3 ; Handle count == 0. brz v2, ebb3 ; Handle count == 0.
v4 = iconst.i32 0 v4 = iconst.i32 0
br ebb2(v4) jump ebb2(v4)
ebb2(v5: i32): ebb2(v5: i32):
v6 = imul_imm v5, 4 v6 = imul_imm v5, 4
v7 = iadd v1, v6 v7 = iadd v1, v6
v8 = heap_load.f32 v7 ; array[i] v8 = heap_load.f32 v7 ; array[i]
v9 = fext.f64 v8 v9 = fpromote.f64 v8
v10 = stack_load.f64 ss1 v10 = stack_load.f64 ss1
v11 = fadd v9, v10 v11 = fadd v9, v10
stack_store v11, ss1 stack_store v11, ss1
@ -20,12 +22,12 @@ ebb2(v5: i32):
v13 = icmp ult v12, v2 v13 = icmp ult v12, v2
brnz v13, ebb2(v12) ; Loop backedge. brnz v13, ebb2(v12) ; Loop backedge.
v14 = stack_load.f64 ss1 v14 = stack_load.f64 ss1
v15 = cvt_utof.f64 v2 v15 = fcvt_from_uint.f64 v2
v16 = fdiv v14, v15 v16 = fdiv v14, v15
v17 = ftrunc.f32 v16 v17 = fdemote.f32 v16
return v17 return v17
ebb3: ebb3:
v100 = f32const qNaN v100 = f32const +NaN
return v100 return v100
} }

3
docs/langref.rst

@ -31,8 +31,7 @@ Here is the same function compiled into Cretonne IL:
.. literalinclude:: example.cton .. literalinclude:: example.cton
:language: cton :language: cton
:linenos: :lines: 2-
:emphasize-lines: 2
The first line of a function definition provides the function *name* and The first line of a function definition provides the function *name* and
the :term:`function signature` which declares the argument and return types. the :term:`function signature` which declares the argument and return types.

64
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) write!(f, "0x0.{0:01$x}p{2}", left_t_bits, digits as usize, emin)
} }
} else if e_bits == max_e_bits { } 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 { if t_bits == 0 {
// Infinity. // Infinity.
write!(f, "Inf") write!(f, "Inf")
@ -375,6 +380,8 @@ fn parse_float(s: &str, w: u8, t: u8) -> Result<u64, &'static str> {
let (sign_bit, s2) = if s.starts_with('-') { let (sign_bit, s2) = if s.starts_with('-') {
(1u64 << t + w, &s[1..]) (1u64 << t + w, &s[1..])
} else if s.starts_with('+') {
(0, &s[1..])
} else { } else {
(0, s) (0, s)
}; };
@ -731,27 +738,29 @@ mod tests {
"0x0.800000p-126"); "0x0.800000p-126");
assert_eq!(Ieee32::new(f32::MIN_POSITIVE * f32::EPSILON).to_string(), assert_eq!(Ieee32::new(f32::MIN_POSITIVE * f32::EPSILON).to_string(),
"0x0.000002p-126"); "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::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"); assert_eq!(Ieee32::new(-f32::NAN).to_string(), "-NaN");
// Construct some qNaNs with payloads. // Construct some qNaNs with payloads.
assert_eq!(Ieee32::from_bits(0x7fc00001).to_string(), "NaN:0x1"); 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(0x7ff00001).to_string(), "+NaN:0x300001");
// Signaling NaNs. // Signaling NaNs.
assert_eq!(Ieee32::from_bits(0x7f800001).to_string(), "sNaN:0x1"); 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(0x7fa00001).to_string(), "+sNaN:0x200001");
} }
#[test] #[test]
fn parse_ieee32() { fn parse_ieee32() {
parse_ok::<Ieee32>("0.0", "0.0"); parse_ok::<Ieee32>("0.0", "0.0");
parse_ok::<Ieee32>("+0.0", "0.0");
parse_ok::<Ieee32>("-0.0", "-0.0"); parse_ok::<Ieee32>("-0.0", "-0.0");
parse_ok::<Ieee32>("0x0", "0.0"); parse_ok::<Ieee32>("0x0", "0.0");
parse_ok::<Ieee32>("0x0.0", "0.0"); parse_ok::<Ieee32>("0x0.0", "0.0");
parse_ok::<Ieee32>("0x.0", "0.0"); parse_ok::<Ieee32>("0x.0", "0.0");
parse_ok::<Ieee32>("0x0.", "0.0"); parse_ok::<Ieee32>("0x0.", "0.0");
parse_ok::<Ieee32>("0x1", "0x1.000000p0"); parse_ok::<Ieee32>("0x1", "0x1.000000p0");
parse_ok::<Ieee32>("+0x1", "0x1.000000p0");
parse_ok::<Ieee32>("-0x1", "-0x1.000000p0"); parse_ok::<Ieee32>("-0x1", "-0x1.000000p0");
parse_ok::<Ieee32>("0x10", "0x1.000000p4"); parse_ok::<Ieee32>("0x10", "0x1.000000p4");
parse_ok::<Ieee32>("0x10.0", "0x1.000000p4"); parse_ok::<Ieee32>("0x10.0", "0x1.000000p4");
@ -793,20 +802,22 @@ mod tests {
parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small"); parse_err::<Ieee32>("0x1.0p-150", "Magnitude too small");
// NaNs and Infs. // NaNs and Infs.
parse_ok::<Ieee32>("Inf", "Inf"); parse_ok::<Ieee32>("Inf", "+Inf");
parse_ok::<Ieee32>("+Inf", "+Inf");
parse_ok::<Ieee32>("-Inf", "-Inf"); parse_ok::<Ieee32>("-Inf", "-Inf");
parse_ok::<Ieee32>("NaN", "NaN"); parse_ok::<Ieee32>("NaN", "+NaN");
parse_ok::<Ieee32>("+NaN", "+NaN");
parse_ok::<Ieee32>("-NaN", "-NaN"); parse_ok::<Ieee32>("-NaN", "-NaN");
parse_ok::<Ieee32>("NaN:0x0", "NaN"); parse_ok::<Ieee32>("NaN:0x0", "+NaN");
parse_err::<Ieee32>("NaN:", "Float must be hexadecimal"); parse_err::<Ieee32>("NaN:", "Float must be hexadecimal");
parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal"); parse_err::<Ieee32>("NaN:0", "Float must be hexadecimal");
parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload"); parse_err::<Ieee32>("NaN:0x", "Invalid NaN payload");
parse_ok::<Ieee32>("NaN:0x000001", "NaN:0x1"); parse_ok::<Ieee32>("NaN:0x000001", "+NaN:0x1");
parse_ok::<Ieee32>("NaN:0x300001", "NaN:0x300001"); parse_ok::<Ieee32>("NaN:0x300001", "+NaN:0x300001");
parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload"); parse_err::<Ieee32>("NaN:0x400001", "Invalid NaN payload");
parse_ok::<Ieee32>("sNaN:0x1", "sNaN:0x1"); parse_ok::<Ieee32>("sNaN:0x1", "+sNaN:0x1");
parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload"); parse_err::<Ieee32>("sNaN:0x0", "Invalid sNaN payload");
parse_ok::<Ieee32>("sNaN:0x200001", "sNaN:0x200001"); parse_ok::<Ieee32>("sNaN:0x200001", "+sNaN:0x200001");
parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload"); parse_err::<Ieee32>("sNaN:0x400001", "Invalid sNaN payload");
} }
@ -829,19 +840,20 @@ mod tests {
"0x0.8000000000000p-1022"); "0x0.8000000000000p-1022");
assert_eq!(Ieee64::new(f64::MIN_POSITIVE * f64::EPSILON).to_string(), assert_eq!(Ieee64::new(f64::MIN_POSITIVE * f64::EPSILON).to_string(),
"0x0.0000000000001p-1022"); "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::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"); assert_eq!(Ieee64::new(-f64::NAN).to_string(), "-NaN");
// Construct some qNaNs with payloads. // 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(), assert_eq!(Ieee64::from_bits(0x7ffc000000000001).to_string(),
"NaN:0x4000000000001"); "+NaN:0x4000000000001");
// Signaling NaNs. // Signaling NaNs.
assert_eq!(Ieee64::from_bits(0x7ff0000000000001).to_string(), assert_eq!(Ieee64::from_bits(0x7ff0000000000001).to_string(),
"sNaN:0x1"); "+sNaN:0x1");
assert_eq!(Ieee64::from_bits(0x7ff4000000000001).to_string(), assert_eq!(Ieee64::from_bits(0x7ff4000000000001).to_string(),
"sNaN:0x4000000000001"); "+sNaN:0x4000000000001");
} }
#[test] #[test]
@ -894,20 +906,20 @@ mod tests {
parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small"); parse_err::<Ieee64>("0x1.0p-1075", "Magnitude too small");
// NaNs and Infs. // NaNs and Infs.
parse_ok::<Ieee64>("Inf", "Inf"); parse_ok::<Ieee64>("Inf", "+Inf");
parse_ok::<Ieee64>("-Inf", "-Inf"); parse_ok::<Ieee64>("-Inf", "-Inf");
parse_ok::<Ieee64>("NaN", "NaN"); parse_ok::<Ieee64>("NaN", "+NaN");
parse_ok::<Ieee64>("-NaN", "-NaN"); parse_ok::<Ieee64>("-NaN", "-NaN");
parse_ok::<Ieee64>("NaN:0x0", "NaN"); parse_ok::<Ieee64>("NaN:0x0", "+NaN");
parse_err::<Ieee64>("NaN:", "Float must be hexadecimal"); parse_err::<Ieee64>("NaN:", "Float must be hexadecimal");
parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal"); parse_err::<Ieee64>("NaN:0", "Float must be hexadecimal");
parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload"); parse_err::<Ieee64>("NaN:0x", "Invalid NaN payload");
parse_ok::<Ieee64>("NaN:0x000001", "NaN:0x1"); parse_ok::<Ieee64>("NaN:0x000001", "+NaN:0x1");
parse_ok::<Ieee64>("NaN:0x4000000000001", "NaN:0x4000000000001"); parse_ok::<Ieee64>("NaN:0x4000000000001", "+NaN:0x4000000000001");
parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload"); parse_err::<Ieee64>("NaN:0x8000000000001", "Invalid NaN payload");
parse_ok::<Ieee64>("sNaN:0x1", "sNaN:0x1"); parse_ok::<Ieee64>("sNaN:0x1", "+sNaN:0x1");
parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload"); parse_err::<Ieee64>("sNaN:0x0", "Invalid sNaN payload");
parse_ok::<Ieee64>("sNaN:0x4000000000001", "sNaN:0x4000000000001"); parse_ok::<Ieee64>("sNaN:0x4000000000001", "+sNaN:0x4000000000001");
parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload"); parse_err::<Ieee64>("sNaN:0x8000000000001", "Invalid sNaN payload");
} }
} }

2
test-all.sh

@ -79,6 +79,6 @@ export CTONUTIL="$topdir/target/release/cton-util"
cd "$topdir" cd "$topdir"
banner "File tests" banner "File tests"
"$CTONUTIL" test filetests "$CTONUTIL" test filetests docs
banner "OK" banner "OK"

Loading…
Cancel
Save