diff --git a/docs/langref.rst b/docs/langref.rst index 61c534ad69..0f49b8f6ed 100644 --- a/docs/langref.rst +++ b/docs/langref.rst @@ -817,14 +817,7 @@ represented as a floating point number. Conversion operations --------------------- -.. inst:: a = bitcast x - - Reinterpret the bits in ``x`` as a different type. - - The input and output types must be storable to memory and of the same size. - A bitcast is equivalent to storing one type and loading the other type from - the same address. - +.. autoinst:: bitcast .. inst:: a = itrunc x .. inst:: a = uext x .. inst:: a = sext x diff --git a/meta/cretonne/base.py b/meta/cretonne/base.py index fd3e4fdcb5..15f23b1abc 100644 --- a/meta/cretonne/base.py +++ b/meta/cretonne/base.py @@ -761,4 +761,29 @@ nearest = Instruction( """, ins=x, outs=a) + +# +# Conversions +# + +Mem = TypeVar( + 'Mem', 'Any type that can be stored in memory', + ints=True, floats=True, simd=True) +MemTo = TypeVar( + 'MemTo', 'Any type that can be stored in memory', + ints=True, floats=True, simd=True) + +x = Operand('x', Mem) +a = Operand('a', MemTo, 'Bits of `x` reinterpreted') + +bitcast = Instruction( + 'bitcast', r""" + Reinterpret the bits in `x` as a different type. + + The input and output types must be storable to memory and of the same + size. A bitcast is equivalent to storing one type and loading the other + type from the same address. + """, + ins=x, outs=a) + instructions.close() diff --git a/src/libcretonne/instructions.rs b/src/libcretonne/instructions.rs index 21138e2ce7..f6ca187511 100644 --- a/src/libcretonne/instructions.rs +++ b/src/libcretonne/instructions.rs @@ -432,6 +432,30 @@ impl ValueTypeSet { }; allowed && self.is_base_type(typ.lane_type()) } + + /// Get an example member of this type set. + /// + /// This is used for error messages to avoid suggesting invalid types. + pub fn example(&self) -> Type { + if self.base != types::VOID { + return self.base; + } + let t = if self.all_ints { + types::I32 + } else if self.all_floats { + types::F32 + } else if self.allow_scalars { + types::B1 + } else { + types::B32 + }; + + if self.allow_scalars { + t + } else { + t.by(4).unwrap() + } + } } /// Operand constraints. This describes the value type constraints on a single `Value` operand. @@ -506,4 +530,49 @@ mod tests { // that? assert_eq!(mem::size_of::(), 16); } + + #[test] + fn value_set() { + use types::*; + + let vts = ValueTypeSet { + allow_scalars: true, + allow_simd: true, + base: VOID, + all_ints: true, + all_floats: false, + all_bools: true, + }; + assert_eq!(vts.example().to_string(), "i32"); + + let vts = ValueTypeSet { + allow_scalars: true, + allow_simd: true, + base: VOID, + all_ints: false, + all_floats: true, + all_bools: true, + }; + assert_eq!(vts.example().to_string(), "f32"); + + let vts = ValueTypeSet { + allow_scalars: false, + allow_simd: true, + base: VOID, + all_ints: false, + all_floats: true, + all_bools: true, + }; + assert_eq!(vts.example().to_string(), "f32x4"); + + let vts = ValueTypeSet { + allow_scalars: false, + allow_simd: true, + base: VOID, + all_ints: false, + all_floats: false, + all_bools: true, + }; + assert_eq!(vts.example().to_string(), "b32x4"); + } } diff --git a/src/libreader/parser.rs b/src/libreader/parser.rs index 7977ccbf54..cf0efb1ffd 100644 --- a/src/libreader/parser.rs +++ b/src/libreader/parser.rs @@ -651,7 +651,10 @@ impl<'a> Parser<'a> { } else if constraints.is_polymorphic() { // This opcode does not support type inference, so the explicit type variable // is required. - return err!(self.loc, "type variable required for polymorphic opcode"); + return err!(self.loc, + "type variable required for polymorphic opcode, e.g. '{}.{}'", + opcode, + constraints.ctrl_typeset().unwrap().example()); } else { // This is a non-polymorphic opcode. No typevar needed. VOID diff --git a/tests/parser/tiny.cton b/tests/parser/tiny.cton index e404985bf8..ae3466b618 100644 --- a/tests/parser/tiny.cton +++ b/tests/parser/tiny.cton @@ -42,3 +42,11 @@ ebb0(vx0: f32, vx1: f32): v1 = fcmp uno, vx0, vx1 v2 = fcmp lt, vx0, vx1 } + +; The bitcast instruction has two type variables: The controlling type variable +; controls the outout type, and the input type is a free variable. +function bitcast(i32, f32) { +ebb0(vx0: i32, vx1: f32): + v0 = bitcast.i8x4 vx0 + v1 = bitcast.i32 vx1 +} diff --git a/tests/parser/tiny.cton.ref b/tests/parser/tiny.cton.ref index 31f5767335..f2404bbf94 100644 --- a/tests/parser/tiny.cton.ref +++ b/tests/parser/tiny.cton.ref @@ -35,3 +35,9 @@ ebb0(vx0: f32, vx1: f32): v1 = fcmp uno, vx0, vx1 v2 = fcmp lt, vx0, vx1 } + +function bitcast(i32, f32) { +ebb0(vx0: i32, vx1: f32): + v0 = bitcast.i8x4 vx0 + v1 = bitcast.i32 vx1 +}