Define icmp and fcmp comparison instructions.

Add new intcc and floatcc operand types for the immediate condition codes on
these instructions.

Add new IntCompare and FloatCompare instruction formats.

Add a generic match_enum() parser function that can match any identifier-like
enumerated operand kind that implements FromStr.

Define the icmp and fcmp instructions in case.py. Include documentation for the
condition codes with these two instructions.
This commit is contained in:
Jakob Stoklund Olesen
2016-07-07 11:20:56 -07:00
parent 70507a3be0
commit 5d8fb0fdc3
9 changed files with 218 additions and 52 deletions

View File

@@ -270,6 +270,14 @@ indicate the different kinds of immediate operands on an instruction.
bits of the operand are interpreted as if the SIMD vector was loaded from bits of the operand are interpreted as if the SIMD vector was loaded from
memory containing the immediate. memory containing the immediate.
.. type:: intcc
An integer condition code. See the :inst:`icmp` instruction for details.
.. type:: floatcc
A floating point condition code. See the :inst:`fcmp` instruction for details.
The two IEEE floating point immediate types :type:`ieee32` and :type:`ieee64` The two IEEE floating point immediate types :type:`ieee32` and :type:`ieee64`
are displayed as hexadecimal floating point literals in the textual IL format. are displayed as hexadecimal floating point literals in the textual IL format.
Decimal floating point literals are not allowed because some computer systems Decimal floating point literals are not allowed because some computer systems
@@ -676,29 +684,7 @@ Vector operations
Integer operations Integer operations
------------------ ------------------
.. inst:: a = icmp Cond, x, y .. autoinst:: icmp
Integer comparison.
:arg Cond: Condition code determining how ``x`` and ``y`` are compared.
:arg Int x: First value to compare.
:arg Int y: Second value to compare.
:result Logic a: With the same number of lanes as ``x`` and ``y``.
The condition code determines if the operands are interpreted as signed or
unsigned integers.
====== ======== =========
Signed Unsigned Condition
====== ======== =========
eq eq Equal
ne ne Not equal
slt ult Less than
sge uge Greater than or equal
sgt ugt Greater than
sle ule Less than or equal
====== ======== =========
.. autoinst:: iadd .. autoinst:: iadd
.. autoinst:: iadd_imm .. autoinst:: iadd_imm
.. autoinst:: isub .. autoinst:: isub
@@ -784,30 +770,7 @@ Floating point operations
These operations generally follow IEEE 754-2008 semantics. These operations generally follow IEEE 754-2008 semantics.
.. inst:: a = fcmp Cond, x, y .. autoinst:: fcmp
Floating point comparison.
:arg Cond: Condition code determining how ``x`` and ``y`` are compared.
:arg x,y: Floating point scalar or vector values of the same type.
:rtype: :type:`b1` or :type:`b1xN` with the same number of lanes as
``x`` and ``y``.
An 'ordered' condition code yields ``false`` if either operand is Nan.
An 'unordered' condition code yields ``true`` if either operand is Nan.
======= ========= =========
Ordered Unordered Condition
======= ========= =========
ord uno None (ord = no NaNs, uno = some NaNs)
oeq ueq Equal
one une Not equal
olt ult Less than
oge uge Greater than or equal
ogt ugt Greater than
ole ule Less than or equal
======= ========= =========
.. inst:: fadd x,y .. inst:: fadd x,y

View File

@@ -11,6 +11,7 @@ use std::str::FromStr;
use entities::*; use entities::*;
use immediates::*; use immediates::*;
use condcodes::*;
use types::{self, Type}; use types::{self, Type};
// Include code generated by `meta/gen_instr.py`. This file contains: // Include code generated by `meta/gen_instr.py`. This file contains:
@@ -175,6 +176,18 @@ pub enum InstructionData {
lane: u8, lane: u8,
arg: Value, arg: Value,
}, },
IntCompare {
opcode: Opcode,
ty: Type,
cond: IntCC,
args: [Value; 2],
},
FloatCompare {
opcode: Opcode,
ty: Type,
cond: FloatCC,
args: [Value; 2],
},
Jump { Jump {
opcode: Opcode, opcode: Opcode,
ty: Type, ty: Type,

View File

@@ -197,6 +197,8 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
Select { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]), Select { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]),
InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]), InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]),
ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane), ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane),
IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
FloatCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
Jump { ref data, .. } => writeln!(w, " {}", data), Jump { ref data, .. } => writeln!(w, " {}", data),
Branch { ref data, .. } => writeln!(w, " {}", data), Branch { ref data, .. } => writeln!(w, " {}", data),
BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table), BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table),

View File

@@ -8,6 +8,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::result; use std::result;
use std::fmt::{self, Display, Formatter, Write}; use std::fmt::{self, Display, Formatter, Write};
use std::str::FromStr;
use std::u32; use std::u32;
use lexer::{self, Lexer, Token}; use lexer::{self, Lexer, Token};
use cretonne::types::{Type, VOID, FunctionName, Signature, ArgumentType, ArgumentExtension}; use cretonne::types::{Type, VOID, FunctionName, Signature, ArgumentType, ArgumentExtension};
@@ -249,7 +250,7 @@ impl<'a> Parser<'a> {
// Match and consume a u8 immediate. // Match and consume a u8 immediate.
// This is used for lane numbers in SIMD vectors. // This is used for lane numbers in SIMD vectors.
fn match_u8(&mut self, err_msg: &str) -> Result<u8> { fn match_uimm8(&mut self, err_msg: &str) -> Result<u8> {
if let Some(Token::Integer(text)) = self.token() { if let Some(Token::Integer(text)) = self.token() {
self.consume(); self.consume();
// Lexer just gives us raw text that looks like an integer. // Lexer just gives us raw text that looks like an integer.
@@ -284,6 +285,16 @@ impl<'a> Parser<'a> {
} }
} }
// Match and consume an enumerated immediate, like one of the condition codes.
fn match_enum<T: FromStr>(&mut self, err_msg: &str) -> Result<T> {
if let Some(Token::Identifier(text)) = self.token() {
self.consume();
text.parse().map_err(|_| self.error(err_msg))
} else {
err!(self.loc, err_msg)
}
}
/// Parse a list of function definitions. /// Parse a list of function definitions.
/// ///
/// This is the top-level parse function matching the whole contents of a file. /// This is the top-level parse function matching the whole contents of a file.
@@ -847,7 +858,7 @@ impl<'a> Parser<'a> {
InstructionFormat::InsertLane => { InstructionFormat::InsertLane => {
let lhs = try!(self.match_value("expected SSA value first operand")); let lhs = try!(self.match_value("expected SSA value first operand"));
try!(self.match_token(Token::Comma, "expected ',' between operands")); try!(self.match_token(Token::Comma, "expected ',' between operands"));
let lane = try!(self.match_u8("expected lane number")); let lane = try!(self.match_uimm8("expected lane number"));
try!(self.match_token(Token::Comma, "expected ',' between operands")); try!(self.match_token(Token::Comma, "expected ',' between operands"));
let rhs = try!(self.match_value("expected SSA value last operand")); let rhs = try!(self.match_value("expected SSA value last operand"));
InstructionData::InsertLane { InstructionData::InsertLane {
@@ -860,7 +871,7 @@ impl<'a> Parser<'a> {
InstructionFormat::ExtractLane => { InstructionFormat::ExtractLane => {
let arg = try!(self.match_value("expected SSA value last operand")); let arg = try!(self.match_value("expected SSA value last operand"));
try!(self.match_token(Token::Comma, "expected ',' between operands")); try!(self.match_token(Token::Comma, "expected ',' between operands"));
let lane = try!(self.match_u8("expected lane number")); let lane = try!(self.match_uimm8("expected lane number"));
InstructionData::ExtractLane { InstructionData::ExtractLane {
opcode: opcode, opcode: opcode,
ty: VOID, ty: VOID,
@@ -868,6 +879,32 @@ impl<'a> Parser<'a> {
arg: arg, arg: arg,
} }
} }
InstructionFormat::IntCompare => {
let cond = try!(self.match_enum("expected intcc condition code"));
try!(self.match_token(Token::Comma, "expected ',' between operands"));
let lhs = try!(self.match_value("expected SSA value first operand"));
try!(self.match_token(Token::Comma, "expected ',' between operands"));
let rhs = try!(self.match_value("expected SSA value second operand"));
InstructionData::IntCompare {
opcode: opcode,
ty: VOID,
cond: cond,
args: [lhs, rhs],
}
}
InstructionFormat::FloatCompare => {
let cond = try!(self.match_enum("expected floatcc condition code"));
try!(self.match_token(Token::Comma, "expected ',' between operands"));
let lhs = try!(self.match_value("expected SSA value first operand"));
try!(self.match_token(Token::Comma, "expected ',' between operands"));
let rhs = try!(self.match_value("expected SSA value second operand"));
InstructionData::FloatCompare {
opcode: opcode,
ty: VOID,
cond: cond,
args: [lhs, rhs],
}
}
InstructionFormat::BranchTable | InstructionFormat::BranchTable |
InstructionFormat::Call => { InstructionFormat::Call => {
unimplemented!(); unimplemented!();

View File

@@ -26,3 +26,19 @@ ebb0:
v1 = extractlane v0, 3 v1 = extractlane v0, 3
v2 = insertlane v0, 1, v1 v2 = insertlane v0, 1, v1
} }
; Integer condition codes.
function icmp(i32, i32) {
ebb0(vx0: i32, vx1: i32):
v0 = icmp eq, vx0, vx1
v1 = icmp ult, vx0, vx1
v2 = icmp sge, vx0, vx1
}
; Floating condition codes.
function fcmp(f32, f32) {
ebb0(vx0: f32, vx1: f32):
v0 = fcmp eq, vx0, vx1
v1 = fcmp uno, vx0, vx1
v2 = fcmp lt, vx0, vx1
}

View File

@@ -21,3 +21,17 @@ ebb0:
v1 = extractlane v0, 3 v1 = extractlane v0, 3
v2 = insertlane v0, 1, v1 v2 = insertlane v0, 1, v1
} }
function icmp(i32, i32) {
ebb0(vx0: i32, vx1: i32):
v0 = icmp eq, vx0, vx1
v1 = icmp ult, vx0, vx1
v2 = icmp sge, vx0, vx1
}
function fcmp(f32, f32) {
ebb0(vx0: f32, vx1: f32):
v0 = fcmp eq, vx0, vx1
v1 = fcmp uno, vx0, vx1
v2 = fcmp lt, vx0, vx1
}

View File

@@ -6,7 +6,7 @@ support.
""" """
from . import TypeVar, Operand, Instruction, InstructionGroup, variable_args from . import TypeVar, Operand, Instruction, InstructionGroup, variable_args
from types import i8, f32, f64 from types import i8, f32, f64
from immediates import imm64, uimm8, ieee32, ieee64, immvector from immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc
import entities import entities
instructions = InstructionGroup("base", "Shared base instruction set") instructions = InstructionGroup("base", "Shared base instruction set")
@@ -217,6 +217,34 @@ extractlane = Instruction(
# Integer arithmetic # Integer arithmetic
# #
a = Operand('a', Int.as_bool())
Cond = Operand('Cond', intcc)
x = Operand('x', Int)
y = Operand('y', Int)
icmp = Instruction(
'icmp', r"""
Integer comparison.
The condition code determines if the operands are interpreted as signed
or unsigned integers.
====== ======== =========
Signed Unsigned Condition
====== ======== =========
eq eq Equal
ne ne Not equal
slt ult Less than
sge uge Greater than or equal
sgt ugt Greater than
sle ule Less than or equal
====== ======== =========
When this instruction compares integer vectors, it returns a boolean
vector of lane-wise comparisons.
""",
ins=(Cond, x, y), outs=a)
a = Operand('a', Int) a = Operand('a', Int)
x = Operand('x', Int) x = Operand('x', Int)
y = Operand('y', Int) y = Operand('y', Int)
@@ -515,4 +543,81 @@ popcnt = Instruction(
""", """,
ins=x, outs=a) ins=x, outs=a)
#
# Floating point.
#
Float = TypeVar(
'Float', 'A scalar or vector floating point type type',
floats=True, simd=True)
Cond = Operand('Cond', floatcc)
x = Operand('x', Float)
y = Operand('y', Float)
a = Operand('a', Float.as_bool())
fcmp = Instruction(
'fcmp', r"""
Floating point comparison.
Two IEEE 754-2008 floating point numbers, `x` and `y`, relate to each
other in exactly one of four ways:
== ==========================================
UN Unordered when one or both numbers is NaN.
EQ When :math:`x = y`. (And :math:`0.0 = -0.0`).
LT When :math:`x < y`.
GT When :math:`x > y`.
== ==========================================
The 14 :type:`floatcc` condition codes each correspond to a subset of
the four relations, except for the empty set which would always be
false, and the full set which would always be true.
The condition codes are divided into 7 'ordered' conditions which don't
include UN, and 7 unordered conditions which all include UN.
+-------+------------+---------+------------+-------------------------+
|Ordered |Unordered |Condition |
+=======+============+=========+============+=========================+
|ord |EQ | LT | GT|uno |UN |NaNs absent / present. |
+-------+------------+---------+------------+-------------------------+
|eq |EQ |ueq |UN | EQ |Equal |
+-------+------------+---------+------------+-------------------------+
|one |LT | GT |ne |UN | LT | GT|Not equal |
+-------+------------+---------+------------+-------------------------+
|lt |LT |ult |UN | LT |Less than |
+-------+------------+---------+------------+-------------------------+
|le |LT | EQ |ule |UN | LT | EQ|Less than or equal |
+-------+------------+---------+------------+-------------------------+
|gt |GT |ugt |UN | GT |Greater than |
+-------+------------+---------+------------+-------------------------+
|ge |GT | EQ |uge |UN | GT | EQ|Greater than or equal |
+-------+------------+---------+------------+-------------------------+
The standard C comparison operators, `<, <=, >, >=`, are all ordered,
so they are false if either operand is NaN. The C equality operator,
`==`, is ordered, and since inequality is defined as the logical
inverse it is *unordered*. They map to the :type:`floatcc` condition
codes as follows:
==== ====== ============
C `Cond` Subset
==== ====== ============
`==` eq EQ
`!=` ne UN | LT | GT
`<` lt LT
`<=` le LT | EQ
`>` gt GT
`>=` ge GT | EQ
==== ====== ============
This subset of condition codes also corresponds to the WebAssembly
floating point comparisons of the same name.
When this instruction compares floating point vectors, it returns a
boolean vector with the results of lane-wise comparisons.
""",
ins=(Cond, x, y), outs=a)
instructions.close() instructions.close()

View File

@@ -8,7 +8,7 @@ in this module.
from . import InstructionFormat, value, variable_args from . import InstructionFormat, value, variable_args
from immediates import imm64, uimm8, ieee32, ieee64, immvector from immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc
from entities import ebb, function, jump_table from entities import ebb, function, jump_table
Nullary = InstructionFormat() Nullary = InstructionFormat()
@@ -33,6 +33,9 @@ Select = InstructionFormat(value, value, value, typevar_operand=1)
InsertLane = InstructionFormat(value, uimm8, value) InsertLane = InstructionFormat(value, uimm8, value)
ExtractLane = InstructionFormat(value, uimm8) ExtractLane = InstructionFormat(value, uimm8)
IntCompare = InstructionFormat(intcc, value, value)
FloatCompare = InstructionFormat(floatcc, value, value)
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)

View File

@@ -29,3 +29,16 @@ ieee64 = ImmediateKind('ieee64', 'A 64-bit immediate floating point number.')
#: A large SIMD vector constant. #: A large SIMD vector constant.
immvector = ImmediateKind('immvector', 'An immediate SIMD vector.') immvector = ImmediateKind('immvector', 'An immediate SIMD vector.')
#: A condition code for comparing integer values.
#:
#: This enumerated operand kind is used for the :cton:inst:`icmp` instruction
#: and corresponds to the `condcodes::IntCC` Rust type.
intcc = ImmediateKind('intcc', 'An integer comparison condition code.')
#: A condition code for comparing floating point values.
#:
#: This enumerated operand kind is used for the :cton:inst:`fcmp` instruction
#: and corresponds to the `condcodes::FloatCC` Rust type.
floatcc = ImmediateKind(
'floatcc', 'A floating point comparison condition code.')