diff --git a/cranelift/codegen/src/data_value.rs b/cranelift/codegen/src/data_value.rs index 965ce1bec5..13aa237674 100644 --- a/cranelift/codegen/src/data_value.rs +++ b/cranelift/codegen/src/data_value.rs @@ -86,6 +86,7 @@ impl DataValue { DataValue::I16(i) => dst[..2].copy_from_slice(&i.to_ne_bytes()[..]), DataValue::I32(i) => dst[..4].copy_from_slice(&i.to_ne_bytes()[..]), DataValue::I64(i) => dst[..8].copy_from_slice(&i.to_ne_bytes()[..]), + DataValue::I128(i) => dst[..16].copy_from_slice(&i.to_ne_bytes()[..]), DataValue::F32(f) => dst[..4].copy_from_slice(&f.bits().to_ne_bytes()[..]), DataValue::F64(f) => dst[..8].copy_from_slice(&f.bits().to_ne_bytes()[..]), DataValue::V128(v) => dst[..16].copy_from_slice(&v[..]), @@ -104,6 +105,7 @@ impl DataValue { types::I16 => DataValue::I16(i16::from_ne_bytes(src[..2].try_into().unwrap())), types::I32 => DataValue::I32(i32::from_ne_bytes(src[..4].try_into().unwrap())), types::I64 => DataValue::I64(i64::from_ne_bytes(src[..8].try_into().unwrap())), + types::I128 => DataValue::I128(i128::from_ne_bytes(src[..16].try_into().unwrap())), types::F32 => DataValue::F32(Ieee32::with_bits(u32::from_ne_bytes( src[..4].try_into().unwrap(), ))), diff --git a/cranelift/reader/src/parser.rs b/cranelift/reader/src/parser.rs index 97b4a7c77d..a0e5a35e3a 100644 --- a/cranelift/reader/src/parser.rs +++ b/cranelift/reader/src/parser.rs @@ -921,6 +921,49 @@ impl<'a> Parser<'a> { } } + // Match and consume an i128 immediate. + fn match_imm128(&mut self, err_msg: &str) -> ParseResult { + if let Some(Token::Integer(text)) = self.token() { + self.consume(); + let negative = text.starts_with('-'); + let positive = text.starts_with('+'); + let text = if negative || positive { + // Strip sign prefix. + &text[1..] + } else { + text + }; + + // Parse the text value; the lexer gives us raw text that looks like an integer. + let value = if text.starts_with("0x") { + // Skip underscores. + let text = text.replace("_", ""); + // Parse it as a i128 in hexadecimal form. + u128::from_str_radix(&text[2..], 16) + .map_err(|_| self.error("unable to parse i128 as a hexadecimal immediate"))? + } else { + // Parse it as a i128 to check for overflow and other issues. + text.parse() + .map_err(|_| self.error("expected i128 decimal immediate"))? + }; + + // Apply sign if necessary. + let signed = if negative { + let value = value.wrapping_neg() as i128; + if value > 0 { + return Err(self.error("negative number too small")); + } + value + } else { + value as i128 + }; + + Ok(signed) + } else { + err!(self.loc, err_msg) + } + } + // Match and consume an optional offset32 immediate. // // Note that this will match an empty string as an empty offset, and that if an offset is @@ -2805,6 +2848,7 @@ impl<'a> Parser<'a> { I16 => DataValue::from(self.match_imm16("expected an i16")?), I32 => DataValue::from(self.match_imm32("expected an i32")?), I64 => DataValue::from(Into::::into(self.match_imm64("expected an i64")?)), + I128 => DataValue::from(self.match_imm128("expected an i64")?), F32 => DataValue::from(self.match_ieee32("expected an f32")?), F64 => DataValue::from(self.match_ieee64("expected an f64")?), _ if ty.is_vector() => { @@ -4126,6 +4170,11 @@ mod tests { assert_eq!(parse("16", I16).to_string(), "16"); assert_eq!(parse("32", I32).to_string(), "32"); assert_eq!(parse("64", I64).to_string(), "64"); + assert_eq!( + parse("0x01234567_01234567_01234567_01234567", I128).to_string(), + "1512366032949150931280199141537564007" + ); + assert_eq!(parse("1234567", I128).to_string(), "1234567"); assert_eq!(parse("0x32.32", F32).to_string(), "0x1.919000p5"); assert_eq!(parse("0x64.64", F64).to_string(), "0x1.9190000000000p6"); assert_eq!(parse("true", B1).to_string(), "true");