diff --git a/docs/langref.rst b/docs/langref.rst index 5fb42c44a2..cff747752a 100644 --- a/docs/langref.rst +++ b/docs/langref.rst @@ -685,7 +685,7 @@ Integer operations .. autoinst:: iadd_cout .. autoinst:: iadd_carry .. autoinst:: isub -.. autoinst:: isub_imm +.. autoinst:: irsub_imm .. autoinst:: isub_bin .. autoinst:: isub_bout .. autoinst:: isub_borrow diff --git a/filetests/parser/tiny.cton b/filetests/parser/tiny.cton index 588223c521..7158441ed2 100644 --- a/filetests/parser/tiny.cton +++ b/filetests/parser/tiny.cton @@ -55,12 +55,14 @@ ebb0(vx0: i32, vx1: i32): v0 = icmp eq, vx0, vx1 v1 = icmp ult, vx0, vx1 v2 = icmp sge, vx0, vx1 + v3 = irsub_imm vx1, 45 } ; sameln: function icmp(i32, i32) { ; nextln: ebb0(vx0: i32, vx1: i32): ; nextln: v0 = icmp eq, vx0, vx1 ; nextln: v1 = icmp ult, vx0, vx1 ; nextln: v2 = icmp sge, vx0, vx1 +; nextln: v3 = irsub_imm vx1, 45 ; nextln: } ; Floating condition codes. diff --git a/lib/cretonne/meta/base/formats.py b/lib/cretonne/meta/base/formats.py index c72d5034f8..7ed047c330 100644 --- a/lib/cretonne/meta/base/formats.py +++ b/lib/cretonne/meta/base/formats.py @@ -22,7 +22,6 @@ UnarySplit = InstructionFormat(VALUE, multiple_results=True) Binary = InstructionFormat(VALUE, VALUE) BinaryImm = InstructionFormat(VALUE, imm64) -BinaryImmRev = InstructionFormat(imm64, VALUE) # Generate result + overflow flag. BinaryOverflow = InstructionFormat(VALUE, VALUE, multiple_results=True) diff --git a/lib/cretonne/meta/base/instructions.py b/lib/cretonne/meta/base/instructions.py index a61f98cefe..41b6ff6c05 100644 --- a/lib/cretonne/meta/base/instructions.py +++ b/lib/cretonne/meta/base/instructions.py @@ -507,22 +507,18 @@ srem_imm = Instruction( allowed. """, ins=(x, Y), outs=a) -# Swap x and y for isub_imm. -X = Operand('X', imm64) -y = Operand('y', iB) - -isub_imm = Instruction( - 'isub_imm', """ - Immediate wrapping subtraction: :math:`a := X - y \pmod{2^B}`. +irsub_imm = Instruction( + 'irsub_imm', """ + Immediate reverse wrapping subtraction: :math:`a := Y - x \pmod{2^B}`. - Also works as integer negation when :math:`X = 0`. Use :inst:`iadd_imm` + Also works as integer negation when :math:`Y = 0`. Use :inst:`iadd_imm` with a negative immediate operand for the reverse immediate subtraction. Polymorphic over all scalar integer types, but does not support vector types. """, - ins=(X, y), outs=a) + ins=(x, Y), outs=a) # # Integer arithmetic with carry and/or borrow. diff --git a/lib/cretonne/meta/cdsl/formats.py b/lib/cretonne/meta/cdsl/formats.py index aa7d384b7c..910afb6052 100644 --- a/lib/cretonne/meta/cdsl/formats.py +++ b/lib/cretonne/meta/cdsl/formats.py @@ -25,6 +25,14 @@ class InstructionFormat(object): produced. Some instructions, like `call`, may have a variable number of results. + The instruction format stores two separate lists of operands: Immediates + and values. Immediate operands (including entity references) are + represented as explicit members in the `InstructionData` variants. The + value operands are stored differently, depending on how many there are. + Beyond a certain point, instruction formats switch to an external value + list for storing value arguments. Value lists can hold an arbitrary number + of values. + All instruction formats must be predefined in the :py:mod:`cretonne.formats` module. @@ -45,8 +53,8 @@ class InstructionFormat(object): immediate operands. """ - # Map (multiple_results, kind, kind, ...) -> InstructionFormat - _registry = dict() # type: Dict[Tuple[bool, Tuple[OperandKind, ...]], InstructionFormat] # noqa + # Map (multiple_results, imm_kinds, num_value_operands) -> format + _registry = dict() # type: Dict[Tuple[bool, Tuple[OperandKind, ...], int, bool], InstructionFormat] # noqa # All existing formats. all_formats = list() # type: List[InstructionFormat] @@ -62,13 +70,11 @@ class InstructionFormat(object): # operands are values or variable argument lists. They are all handled # specially. self.imm_members = list() # type: List[str] - # Operand kinds for the immediate operands. - self.imm_kinds = list() # type: List[OperandKind] # The number of value operands stored in the format, or `None` when # `has_value_list` is set. self.num_value_operands = 0 - - sig_kinds = tuple(self._process_member_names(kinds)) + # Operand kinds for the immediate operands. + self.imm_kinds = tuple(self._process_member_names(kinds)) # The typevar_operand argument must point to a 'value' operand. self.typevar_operand = kwargs.get('typevar_operand', None) # type: int @@ -81,7 +87,10 @@ class InstructionFormat(object): self.typevar_operand = 0 # Compute a signature for the global registry. - sig = (self.multiple_results, sig_kinds) + sig = ( + self.multiple_results, self.imm_kinds, + self.num_value_operands, + self.has_value_list) if sig in InstructionFormat._registry: raise RuntimeError( "Format '{}' has the same signature as existing format '{}'" @@ -98,9 +107,9 @@ class InstructionFormat(object): pair. The member names correspond to members in the Rust `InstructionData` data structure. - Update the fields `num_value_operands`, `imm_kinds`, and `imm_members`. + Update the fields `num_value_operands` and `imm_members`. - Yields the operand kinds. + Yields the immediate operand kinds. """ for arg in kinds: if isinstance(arg, OperandKind): @@ -116,16 +125,14 @@ class InstructionFormat(object): # We require a value list for storage of variable arguments. assert self.has_value_list, "Need a value list" else: - self.imm_kinds.append(k) self.imm_members.append(member) - - yield k + yield k def __str__(self): # type: () -> str args = ', '.join('{}: {}'.format(m, k) for m, k in zip(self.imm_members, self.imm_kinds)) - return '{}({}, values={})'.format( + return '{}(imms=({}), vals={})'.format( self.name, args, self.num_value_operands) def __getattr__(self, attr): @@ -162,7 +169,13 @@ class InstructionFormat(object): multiple_results = outs[0].kind == VARIABLE_ARGS else: multiple_results = len(outs) > 1 - sig = (multiple_results, tuple(op.kind for op in ins)) + + # Construct a signature. + imm_kinds = tuple(op.kind for op in ins if op.is_immediate()) + num_values = sum(1 for op in ins if op.is_value()) + has_varargs = (VARIABLE_ARGS in tuple(op.kind for op in ins)) + + sig = (multiple_results, imm_kinds, num_values, has_varargs) if sig not in InstructionFormat._registry: raise RuntimeError( "No instruction format matches ins = ({}){}".format( diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index 4cabfe6698..09167907be 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -145,13 +145,6 @@ pub enum InstructionData { arg: Value, imm: Imm64, }, - // Same as `BinaryImm`, but the immediate is the left-hand-side operand. - BinaryImmRev { - opcode: Opcode, - ty: Type, - arg: Value, - imm: Imm64, - }, BinaryOverflow { opcode: Opcode, ty: Type, diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index 8f120f447a..57d31d2e5c 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -237,7 +237,6 @@ fn write_instruction(w: &mut Write, UnarySplit { arg, .. } => writeln!(w, " {}", arg), Binary { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm), - BinaryImmRev { imm, arg, .. } => writeln!(w, " {}, {}", imm, arg), BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]), TernaryOverflow { ref data, .. } => writeln!(w, " {}", data), diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index 72f43a043d..1e5e194785 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -177,7 +177,6 @@ impl<'a> Context<'a> { InstructionData::Unary { ref mut arg, .. } | InstructionData::UnarySplit { ref mut arg, .. } | InstructionData::BinaryImm { ref mut arg, .. } | - InstructionData::BinaryImmRev { ref mut arg, .. } | InstructionData::ExtractLane { ref mut arg, .. } | InstructionData::BranchTable { ref mut arg, .. } => { self.map.rewrite_value(arg, loc)?; @@ -1368,17 +1367,6 @@ impl<'a> Parser<'a> { imm: rhs, } } - InstructionFormat::BinaryImmRev => { - let lhs = self.match_imm64("expected immediate integer first operand")?; - self.match_token(Token::Comma, "expected ',' between operands")?; - let rhs = self.match_value("expected SSA value second operand")?; - InstructionData::BinaryImmRev { - opcode: opcode, - ty: VOID, - imm: lhs, - arg: rhs, - } - } InstructionFormat::BinaryOverflow => { let lhs = self.match_value("expected SSA value first operand")?; self.match_token(Token::Comma, "expected ',' between operands")?;