Browse Source

Separate immediate and value operands in the instruction format.

Instruction formats are now identified by a signature that doesn't
include the ordering of value operands relative to immediate operands.

This means that the BinaryRev instruction format becomes redundant, so
delete it. The isub_imm instruction was the only one using that format.
Rename it to irsub_imm to make it clear what it does now that it is
printed as 'irsub_imm v2, 45'.
pull/3/head
Jakob Stoklund Olesen 8 years ago
parent
commit
60daf3e76b
  1. 2
      docs/langref.rst
  2. 2
      filetests/parser/tiny.cton
  3. 1
      lib/cretonne/meta/base/formats.py
  4. 14
      lib/cretonne/meta/base/instructions.py
  5. 39
      lib/cretonne/meta/cdsl/formats.py
  6. 7
      lib/cretonne/src/ir/instructions.rs
  7. 1
      lib/cretonne/src/write.rs
  8. 12
      lib/reader/src/parser.rs

2
docs/langref.rst

@ -685,7 +685,7 @@ Integer operations
.. autoinst:: iadd_cout .. autoinst:: iadd_cout
.. autoinst:: iadd_carry .. autoinst:: iadd_carry
.. autoinst:: isub .. autoinst:: isub
.. autoinst:: isub_imm .. autoinst:: irsub_imm
.. autoinst:: isub_bin .. autoinst:: isub_bin
.. autoinst:: isub_bout .. autoinst:: isub_bout
.. autoinst:: isub_borrow .. autoinst:: isub_borrow

2
filetests/parser/tiny.cton

@ -55,12 +55,14 @@ ebb0(vx0: i32, vx1: i32):
v0 = icmp eq, vx0, vx1 v0 = icmp eq, vx0, vx1
v1 = icmp ult, vx0, vx1 v1 = icmp ult, vx0, vx1
v2 = icmp sge, vx0, vx1 v2 = icmp sge, vx0, vx1
v3 = irsub_imm vx1, 45
} }
; sameln: function icmp(i32, i32) { ; sameln: function icmp(i32, i32) {
; nextln: ebb0(vx0: i32, vx1: i32): ; nextln: ebb0(vx0: i32, vx1: i32):
; nextln: v0 = icmp eq, vx0, vx1 ; nextln: v0 = icmp eq, vx0, vx1
; nextln: v1 = icmp ult, vx0, vx1 ; nextln: v1 = icmp ult, vx0, vx1
; nextln: v2 = icmp sge, vx0, vx1 ; nextln: v2 = icmp sge, vx0, vx1
; nextln: v3 = irsub_imm vx1, 45
; nextln: } ; nextln: }
; Floating condition codes. ; Floating condition codes.

1
lib/cretonne/meta/base/formats.py

@ -22,7 +22,6 @@ UnarySplit = InstructionFormat(VALUE, multiple_results=True)
Binary = InstructionFormat(VALUE, VALUE) Binary = InstructionFormat(VALUE, VALUE)
BinaryImm = InstructionFormat(VALUE, imm64) BinaryImm = InstructionFormat(VALUE, imm64)
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)

14
lib/cretonne/meta/base/instructions.py

@ -507,22 +507,18 @@ srem_imm = Instruction(
allowed. """, allowed. """,
ins=(x, Y), outs=a) ins=(x, Y), outs=a)
# Swap x and y for isub_imm. irsub_imm = Instruction(
X = Operand('X', imm64) 'irsub_imm', """
y = Operand('y', iB) Immediate reverse wrapping subtraction: :math:`a := Y - x \pmod{2^B}`.
isub_imm = Instruction(
'isub_imm', """
Immediate wrapping subtraction: :math:`a := X - y \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 with a negative immediate operand for the reverse immediate
subtraction. subtraction.
Polymorphic over all scalar integer types, but does not support vector Polymorphic over all scalar integer types, but does not support vector
types. types.
""", """,
ins=(X, y), outs=a) ins=(x, Y), outs=a)
# #
# Integer arithmetic with carry and/or borrow. # Integer arithmetic with carry and/or borrow.

39
lib/cretonne/meta/cdsl/formats.py

@ -25,6 +25,14 @@ class InstructionFormat(object):
produced. Some instructions, like `call`, may have a variable number of produced. Some instructions, like `call`, may have a variable number of
results. 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 All instruction formats must be predefined in the
:py:mod:`cretonne.formats` module. :py:mod:`cretonne.formats` module.
@ -45,8 +53,8 @@ class InstructionFormat(object):
immediate operands. immediate operands.
""" """
# Map (multiple_results, kind, kind, ...) -> InstructionFormat # Map (multiple_results, imm_kinds, num_value_operands) -> format
_registry = dict() # type: Dict[Tuple[bool, Tuple[OperandKind, ...]], InstructionFormat] # noqa _registry = dict() # type: Dict[Tuple[bool, Tuple[OperandKind, ...], int, bool], InstructionFormat] # noqa
# All existing formats. # All existing formats.
all_formats = list() # type: List[InstructionFormat] all_formats = list() # type: List[InstructionFormat]
@ -62,13 +70,11 @@ class InstructionFormat(object):
# operands are values or variable argument lists. They are all handled # operands are values or variable argument lists. They are all handled
# specially. # specially.
self.imm_members = list() # type: List[str] 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 # The number of value operands stored in the format, or `None` when
# `has_value_list` is set. # `has_value_list` is set.
self.num_value_operands = 0 self.num_value_operands = 0
# Operand kinds for the immediate operands.
sig_kinds = tuple(self._process_member_names(kinds)) self.imm_kinds = tuple(self._process_member_names(kinds))
# The typevar_operand argument must point to a 'value' operand. # The typevar_operand argument must point to a 'value' operand.
self.typevar_operand = kwargs.get('typevar_operand', None) # type: int self.typevar_operand = kwargs.get('typevar_operand', None) # type: int
@ -81,7 +87,10 @@ class InstructionFormat(object):
self.typevar_operand = 0 self.typevar_operand = 0
# Compute a signature for the global registry. # 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: if sig in InstructionFormat._registry:
raise RuntimeError( raise RuntimeError(
"Format '{}' has the same signature as existing format '{}'" "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 pair. The member names correspond to members in the Rust
`InstructionData` data structure. `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: for arg in kinds:
if isinstance(arg, OperandKind): if isinstance(arg, OperandKind):
@ -116,16 +125,14 @@ class InstructionFormat(object):
# We require a value list for storage of variable arguments. # We require a value list for storage of variable arguments.
assert self.has_value_list, "Need a value list" assert self.has_value_list, "Need a value list"
else: else:
self.imm_kinds.append(k)
self.imm_members.append(member) self.imm_members.append(member)
yield k yield k
def __str__(self): def __str__(self):
# type: () -> str # type: () -> str
args = ', '.join('{}: {}'.format(m, k) args = ', '.join('{}: {}'.format(m, k)
for m, k in zip(self.imm_members, self.imm_kinds)) 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) self.name, args, self.num_value_operands)
def __getattr__(self, attr): def __getattr__(self, attr):
@ -162,7 +169,13 @@ class InstructionFormat(object):
multiple_results = outs[0].kind == VARIABLE_ARGS multiple_results = outs[0].kind == VARIABLE_ARGS
else: else:
multiple_results = len(outs) > 1 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: if sig not in InstructionFormat._registry:
raise RuntimeError( raise RuntimeError(
"No instruction format matches ins = ({}){}".format( "No instruction format matches ins = ({}){}".format(

7
lib/cretonne/src/ir/instructions.rs

@ -145,13 +145,6 @@ pub enum InstructionData {
arg: Value, arg: Value,
imm: Imm64, imm: Imm64,
}, },
// Same as `BinaryImm`, but the immediate is the left-hand-side operand.
BinaryImmRev {
opcode: Opcode,
ty: Type,
arg: Value,
imm: Imm64,
},
BinaryOverflow { BinaryOverflow {
opcode: Opcode, opcode: Opcode,
ty: Type, ty: Type,

1
lib/cretonne/src/write.rs

@ -237,7 +237,6 @@ fn write_instruction(w: &mut Write,
UnarySplit { arg, .. } => writeln!(w, " {}", arg), UnarySplit { arg, .. } => writeln!(w, " {}", arg),
Binary { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), Binary { args, .. } => writeln!(w, " {}, {}", args[0], args[1]),
BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm), BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm),
BinaryImmRev { imm, arg, .. } => writeln!(w, " {}, {}", imm, arg),
BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]),
Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]), Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]),
TernaryOverflow { ref data, .. } => writeln!(w, " {}", data), TernaryOverflow { ref data, .. } => writeln!(w, " {}", data),

12
lib/reader/src/parser.rs

@ -177,7 +177,6 @@ impl<'a> Context<'a> {
InstructionData::Unary { ref mut arg, .. } | InstructionData::Unary { ref mut arg, .. } |
InstructionData::UnarySplit { ref mut arg, .. } | InstructionData::UnarySplit { ref mut arg, .. } |
InstructionData::BinaryImm { ref mut arg, .. } | InstructionData::BinaryImm { ref mut arg, .. } |
InstructionData::BinaryImmRev { ref mut arg, .. } |
InstructionData::ExtractLane { ref mut arg, .. } | InstructionData::ExtractLane { ref mut arg, .. } |
InstructionData::BranchTable { ref mut arg, .. } => { InstructionData::BranchTable { ref mut arg, .. } => {
self.map.rewrite_value(arg, loc)?; self.map.rewrite_value(arg, loc)?;
@ -1368,17 +1367,6 @@ impl<'a> Parser<'a> {
imm: rhs, 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 => { InstructionFormat::BinaryOverflow => {
let lhs = self.match_value("expected SSA value first operand")?; let lhs = self.match_value("expected SSA value first operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?; self.match_token(Token::Comma, "expected ',' between operands")?;

Loading…
Cancel
Save