Add meta definition for bitcast.

This instruction uses two type variables: input and output. Make sure that our
parser can handle it. The output type variable annotation is mandatory.

Add a ValueTypeSet::example() method which is used to provide better diagnostics
for a missing type variable.
This commit is contained in:
Jakob Stoklund Olesen
2016-07-07 13:40:16 -07:00
parent 2bfb4ca5b7
commit 4a929f5e41
6 changed files with 113 additions and 9 deletions

View File

@@ -817,14 +817,7 @@ represented as a floating point number.
Conversion operations Conversion operations
--------------------- ---------------------
.. inst:: a = bitcast x .. autoinst:: bitcast
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.
.. inst:: a = itrunc x .. inst:: a = itrunc x
.. inst:: a = uext x .. inst:: a = uext x
.. inst:: a = sext x .. inst:: a = sext x

View File

@@ -761,4 +761,29 @@ nearest = Instruction(
""", """,
ins=x, outs=a) 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() instructions.close()

View File

@@ -432,6 +432,30 @@ impl ValueTypeSet {
}; };
allowed && self.is_base_type(typ.lane_type()) 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. /// Operand constraints. This describes the value type constraints on a single `Value` operand.
@@ -506,4 +530,49 @@ mod tests {
// that? // that?
assert_eq!(mem::size_of::<InstructionData>(), 16); assert_eq!(mem::size_of::<InstructionData>(), 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");
}
} }

View File

@@ -651,7 +651,10 @@ impl<'a> Parser<'a> {
} else if constraints.is_polymorphic() { } else if constraints.is_polymorphic() {
// This opcode does not support type inference, so the explicit type variable // This opcode does not support type inference, so the explicit type variable
// is required. // 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 { } else {
// This is a non-polymorphic opcode. No typevar needed. // This is a non-polymorphic opcode. No typevar needed.
VOID VOID

View File

@@ -42,3 +42,11 @@ ebb0(vx0: f32, vx1: f32):
v1 = fcmp uno, vx0, vx1 v1 = fcmp uno, vx0, vx1
v2 = fcmp lt, 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
}

View File

@@ -35,3 +35,9 @@ ebb0(vx0: f32, vx1: f32):
v1 = fcmp uno, vx0, vx1 v1 = fcmp uno, vx0, vx1
v2 = fcmp lt, vx0, vx1 v2 = fcmp lt, vx0, vx1
} }
function bitcast(i32, f32) {
ebb0(vx0: i32, vx1: f32):
v0 = bitcast.i8x4 vx0
v1 = bitcast.i32 vx1
}