Implement select and vselect instructions.
This gives us the opportunity to use the AsBool derived type variables and a Select instruction format with a non-default typevar_operand setting.
This commit is contained in:
@@ -656,35 +656,12 @@ load a constant into an SSA value.
|
|||||||
.. autoinst:: f32const
|
.. autoinst:: f32const
|
||||||
.. autoinst:: f64const
|
.. autoinst:: f64const
|
||||||
.. autoinst:: vconst
|
.. autoinst:: vconst
|
||||||
|
.. autoinst:: select
|
||||||
.. 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.
|
|
||||||
|
|
||||||
Vector operations
|
Vector operations
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
.. inst:: a = vselect c, x, y
|
.. autoinst:: vselect
|
||||||
|
|
||||||
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``.
|
|
||||||
|
|
||||||
.. inst:: a = vbuild x, y, z, ...
|
.. inst:: a = vbuild x, y, z, ...
|
||||||
|
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ class TypeVar(object):
|
|||||||
if self.is_derived:
|
if self.is_derived:
|
||||||
assert derived_func
|
assert derived_func
|
||||||
self.derived_func = derived_func
|
self.derived_func = derived_func
|
||||||
|
self.name = '{}({})'.format(derived_func, base.name)
|
||||||
else:
|
else:
|
||||||
self.type_set = TypeSet(
|
self.type_set = TypeSet(
|
||||||
allow_scalars=scalars,
|
allow_scalars=scalars,
|
||||||
@@ -303,18 +304,14 @@ class TypeVar(object):
|
|||||||
When this type variable assumes a scalar type, the derived type will be
|
When this type variable assumes a scalar type, the derived type will be
|
||||||
the same scalar type.
|
the same scalar type.
|
||||||
"""
|
"""
|
||||||
return TypeVar(
|
return TypeVar(None, None, base=self, derived_func='Lane')
|
||||||
"Lane type of " + self.name, '',
|
|
||||||
base=self, derived_func='Lane')
|
|
||||||
|
|
||||||
def as_bool(self):
|
def as_bool(self):
|
||||||
"""
|
"""
|
||||||
Return a derived type variable that has the same vector geometry as
|
Return a derived type variable that has the same vector geometry as
|
||||||
this type variable, but with boolean lanes. Scalar types map to `b1`.
|
this type variable, but with boolean lanes. Scalar types map to `b1`.
|
||||||
"""
|
"""
|
||||||
return TypeVar(
|
return TypeVar(None, None, base=self, derived_func='AsBool')
|
||||||
self.name + " as boolean", '',
|
|
||||||
base=self, derived_func='AsBool')
|
|
||||||
|
|
||||||
def operand_kind(self):
|
def operand_kind(self):
|
||||||
# When a `TypeVar` object is used to describe the type of an `Operand`
|
# 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.
|
# No other derived typevars allowed.
|
||||||
if typ is not tv:
|
if typ is not tv:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"type variable {} must not be derived from {}"
|
"{}: type variable {} must be derived from {}"
|
||||||
.format(typ.name, tv.name))
|
.format(self.ins[opidx], typ.name, ctrl_typevar))
|
||||||
# Other free type variables can only be used once each.
|
# Other free type variables can only be used once each.
|
||||||
if tv in other_tvs:
|
if tv in other_tvs:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ Testable = TypeVar(
|
|||||||
TxN = TypeVar(
|
TxN = TypeVar(
|
||||||
'%Tx%N', 'A SIMD vector type',
|
'%Tx%N', 'A SIMD vector type',
|
||||||
ints=True, floats=True, bools=True, scalars=False, simd=True)
|
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
|
# Control flow
|
||||||
@@ -140,6 +143,41 @@ vconst = Instruction(
|
|||||||
ins=N, outs=a)
|
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
|
# Integer arithmetic
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ BinaryImmRev = InstructionFormat(imm64, value)
|
|||||||
# Generate result + overflow flag.
|
# Generate result + overflow flag.
|
||||||
BinaryOverflow = InstructionFormat(value, value, multiple_results=True)
|
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)
|
Jump = InstructionFormat(ebb, variable_args, boxed_storage=True)
|
||||||
Branch = InstructionFormat(value, ebb, variable_args, boxed_storage=True)
|
Branch = InstructionFormat(value, ebb, variable_args, boxed_storage=True)
|
||||||
BranchTable = InstructionFormat(value, jump_table)
|
BranchTable = InstructionFormat(value, jump_table)
|
||||||
|
|||||||
@@ -158,6 +158,11 @@ pub enum InstructionData {
|
|||||||
second_result: Value,
|
second_result: Value,
|
||||||
args: [Value; 2],
|
args: [Value; 2],
|
||||||
},
|
},
|
||||||
|
Select {
|
||||||
|
opcode: Opcode,
|
||||||
|
ty: Type,
|
||||||
|
args: [Value; 3],
|
||||||
|
},
|
||||||
Jump {
|
Jump {
|
||||||
opcode: Opcode,
|
opcode: Opcode,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
@@ -295,13 +300,13 @@ impl InstructionData {
|
|||||||
///
|
///
|
||||||
/// Bits 4-7:
|
/// Bits 4-7:
|
||||||
/// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
|
/// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
|
||||||
///
|
///
|
||||||
/// Bits 8-15:
|
/// Bits 8-15:
|
||||||
/// Offset into `OPERAND_CONSTRAINT` table of the descriptors for this opcode. The first
|
/// 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_results()` entries describe the result constraints, then follows constraints for the
|
||||||
/// fixed `Value` input operands. The number of `Value` inputs isdetermined by the instruction
|
/// fixed `Value` input operands. The number of `Value` inputs isdetermined by the instruction
|
||||||
/// format.
|
/// format.
|
||||||
///
|
///
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct OpcodeConstraints(u16);
|
pub struct OpcodeConstraints(u16);
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
BinaryImm { opcode, lhs, rhs, .. } => writeln!(w, "{} {}, {}", opcode, lhs, rhs),
|
||||||
BinaryImmRev { 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]),
|
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),
|
Jump { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data),
|
||||||
Branch { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data),
|
Branch { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data),
|
||||||
BranchTable { opcode, arg, table, .. } => writeln!(w, "{} {}, {}", opcode, arg, table),
|
BranchTable { opcode, arg, table, .. } => writeln!(w, "{} {}, {}", opcode, arg, table),
|
||||||
|
|||||||
@@ -668,6 +668,7 @@ impl<'a> Parser<'a> {
|
|||||||
args: [lhs, rhs],
|
args: [lhs, rhs],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InstructionFormat::Select |
|
||||||
InstructionFormat::Jump |
|
InstructionFormat::Jump |
|
||||||
InstructionFormat::Branch |
|
InstructionFormat::Branch |
|
||||||
InstructionFormat::BranchTable |
|
InstructionFormat::BranchTable |
|
||||||
|
|||||||
Reference in New Issue
Block a user