diff --git a/docs/langref.rst b/docs/langref.rst index ca58a9b273..05ebfa9e05 100644 --- a/docs/langref.rst +++ b/docs/langref.rst @@ -656,35 +656,12 @@ load a constant into an SSA value. .. autoinst:: f32const .. autoinst:: f64const .. autoinst:: vconst - -.. inst:: a = select c, x, y - - Conditional select. - - :arg b1 c: Controlling flag. - :arg T x: Value to return when ``c`` is true. - :arg T y: Value to return when ``c`` is false. Must be same type as ``x``. - :result T a: Same type as ``x`` and ``y``. - - This instruction selects whole values. Use :inst:`vselect` for lane-wise - selection. +.. autoinst:: select Vector operations ----------------- -.. inst:: a = vselect c, x, y - - Vector lane select. - - Select lanes from ``x`` or ``y`` controlled by the lanes of the boolean - vector ``c``. - - :arg b1xN c: Controlling flag vector. - :arg TxN x: Vector with lanes selected by the true lanes of ``c``. - Must be a vector type with the same number of lanes as ``c``. - :arg TxN y: Vector with lanes selected by the false lanes of ``c``. - Must be same type as ``x``. - :result TxN a: Same type as ``x`` and ``y``. +.. autoinst:: vselect .. inst:: a = vbuild x, y, z, ... diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index 2c737c2e7e..c0eec9e970 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -283,6 +283,7 @@ class TypeVar(object): if self.is_derived: assert derived_func self.derived_func = derived_func + self.name = '{}({})'.format(derived_func, base.name) else: self.type_set = TypeSet( allow_scalars=scalars, @@ -303,18 +304,14 @@ class TypeVar(object): When this type variable assumes a scalar type, the derived type will be the same scalar type. """ - return TypeVar( - "Lane type of " + self.name, '', - base=self, derived_func='Lane') + return TypeVar(None, None, base=self, derived_func='Lane') def as_bool(self): """ Return a derived type variable that has the same vector geometry as this type variable, but with boolean lanes. Scalar types map to `b1`. """ - return TypeVar( - self.name + " as boolean", '', - base=self, derived_func='AsBool') + return TypeVar(None, None, base=self, derived_func='AsBool') def operand_kind(self): # When a `TypeVar` object is used to describe the type of an `Operand` @@ -607,8 +604,8 @@ class Instruction(object): # No other derived typevars allowed. if typ is not tv: raise RuntimeError( - "type variable {} must not be derived from {}" - .format(typ.name, tv.name)) + "{}: type variable {} must be derived from {}" + .format(self.ins[opidx], typ.name, ctrl_typevar)) # Other free type variables can only be used once each. if tv in other_tvs: raise RuntimeError( diff --git a/meta/cretonne/base.py b/meta/cretonne/base.py index 9e13377ed6..c28c3724a2 100644 --- a/meta/cretonne/base.py +++ b/meta/cretonne/base.py @@ -19,6 +19,9 @@ Testable = TypeVar( TxN = TypeVar( '%Tx%N', 'A SIMD vector type', ints=True, floats=True, bools=True, scalars=False, simd=True) +Any = TypeVar( + 'Any', 'Any integer, float, or boolean scalar or vector type', + ints=True, floats=True, bools=True, scalars=True, simd=True) # # Control flow @@ -140,6 +143,41 @@ vconst = Instruction( ins=N, outs=a) # +# Generics. +# + +c = Operand('c', Testable, doc='Controlling value to test') +x = Operand('x', Any, doc='Value to use when `c` is true') +y = Operand('y', Any, doc='Value to use when `c` is false') +a = Operand('a', Any) + +select = Instruction( + 'select', r""" + Conditional select. + + This instruction selects whole values. Use :inst:`vselect` for + lane-wise selection. + """, + ins=(c, x, y), outs=a) + +# +# Vector operations +# + +c = Operand('c', TxN.as_bool(), doc='Controlling vector') +x = Operand('x', TxN, doc='Value to use where `c` is true') +y = Operand('y', TxN, doc='Value to use where `c` is false') +a = Operand('a', TxN) + +vselect = Instruction( + 'vselect', r""" + Vector lane select. + + Select lanes from ``x`` or ``y`` controlled by the lanes of the boolean + vector ``c``. + """, + ins=(c, x, y), outs=a) +# # Integer arithmetic # diff --git a/meta/cretonne/formats.py b/meta/cretonne/formats.py index 261b400321..4843befea9 100644 --- a/meta/cretonne/formats.py +++ b/meta/cretonne/formats.py @@ -26,6 +26,10 @@ BinaryImmRev = InstructionFormat(imm64, value) # Generate result + overflow flag. BinaryOverflow = InstructionFormat(value, value, multiple_results=True) +# The select instructions are controlled by the second value operand. +# The first value operand is the controlling flag whisch has a derived type. +Select = InstructionFormat(value, value, value, typevar_operand=1) + Jump = InstructionFormat(ebb, variable_args, boxed_storage=True) Branch = InstructionFormat(value, ebb, variable_args, boxed_storage=True) BranchTable = InstructionFormat(value, jump_table) diff --git a/src/libcretonne/instructions.rs b/src/libcretonne/instructions.rs index c6b353ae9c..d1861fb669 100644 --- a/src/libcretonne/instructions.rs +++ b/src/libcretonne/instructions.rs @@ -158,6 +158,11 @@ pub enum InstructionData { second_result: Value, args: [Value; 2], }, + Select { + opcode: Opcode, + ty: Type, + args: [Value; 3], + }, Jump { opcode: Opcode, ty: Type, @@ -295,13 +300,13 @@ impl InstructionData { /// /// Bits 4-7: /// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`. -/// +/// /// Bits 8-15: /// Offset into `OPERAND_CONSTRAINT` table of the descriptors for this opcode. The first /// `fixed_results()` entries describe the result constraints, then follows constraints for the /// fixed `Value` input operands. The number of `Value` inputs isdetermined by the instruction /// format. -/// +/// #[derive(Clone, Copy)] pub struct OpcodeConstraints(u16); diff --git a/src/libcretonne/write.rs b/src/libcretonne/write.rs index d3a676293d..e6eb3a477f 100644 --- a/src/libcretonne/write.rs +++ b/src/libcretonne/write.rs @@ -156,6 +156,9 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result { BinaryImm { opcode, lhs, rhs, .. } => writeln!(w, "{} {}, {}", opcode, lhs, rhs), BinaryImmRev { opcode, lhs, rhs, .. } => writeln!(w, "{} {}, {}", opcode, lhs, rhs), BinaryOverflow { opcode, args, .. } => writeln!(w, "{} {}, {}", opcode, args[0], args[1]), + Select { opcode, args, .. } => { + writeln!(w, "{} {}, {}, {}", opcode, args[0], args[1], args[2]) + } Jump { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data), Branch { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data), BranchTable { opcode, arg, table, .. } => writeln!(w, "{} {}, {}", opcode, arg, table), diff --git a/src/libreader/parser.rs b/src/libreader/parser.rs index 2247259530..6aab089330 100644 --- a/src/libreader/parser.rs +++ b/src/libreader/parser.rs @@ -668,6 +668,7 @@ impl<'a> Parser<'a> { args: [lhs, rhs], } } + InstructionFormat::Select | InstructionFormat::Jump | InstructionFormat::Branch | InstructionFormat::BranchTable |