diff --git a/cranelift/docs/langref.rst b/cranelift/docs/langref.rst index 8bf890b080..7df404e02c 100644 --- a/cranelift/docs/langref.rst +++ b/cranelift/docs/langref.rst @@ -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 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` are displayed as hexadecimal floating point literals in the textual IL format. Decimal floating point literals are not allowed because some computer systems @@ -676,29 +684,7 @@ Vector operations Integer operations ------------------ -.. inst:: a = icmp Cond, x, y - - 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:: icmp .. autoinst:: iadd .. autoinst:: iadd_imm .. autoinst:: isub @@ -784,30 +770,7 @@ Floating point operations These operations generally follow IEEE 754-2008 semantics. -.. inst:: a = fcmp Cond, x, y - - 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 - ======= ========= ========= +.. autoinst:: fcmp .. inst:: fadd x,y diff --git a/cranelift/src/libcretonne/instructions.rs b/cranelift/src/libcretonne/instructions.rs index d8880c28ed..106f506e47 100644 --- a/cranelift/src/libcretonne/instructions.rs +++ b/cranelift/src/libcretonne/instructions.rs @@ -11,6 +11,7 @@ use std::str::FromStr; use entities::*; use immediates::*; +use condcodes::*; use types::{self, Type}; // Include code generated by `meta/gen_instr.py`. This file contains: @@ -175,6 +176,18 @@ pub enum InstructionData { lane: u8, arg: Value, }, + IntCompare { + opcode: Opcode, + ty: Type, + cond: IntCC, + args: [Value; 2], + }, + FloatCompare { + opcode: Opcode, + ty: Type, + cond: FloatCC, + args: [Value; 2], + }, Jump { opcode: Opcode, ty: Type, diff --git a/cranelift/src/libcretonne/write.rs b/cranelift/src/libcretonne/write.rs index e0d19aa5a8..217d670afc 100644 --- a/cranelift/src/libcretonne/write.rs +++ b/cranelift/src/libcretonne/write.rs @@ -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]), InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]), 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), Branch { ref data, .. } => writeln!(w, " {}", data), BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table), diff --git a/cranelift/src/libreader/parser.rs b/cranelift/src/libreader/parser.rs index ca8f56232b..a17449008e 100644 --- a/cranelift/src/libreader/parser.rs +++ b/cranelift/src/libreader/parser.rs @@ -8,6 +8,7 @@ use std::collections::HashMap; use std::result; use std::fmt::{self, Display, Formatter, Write}; +use std::str::FromStr; use std::u32; use lexer::{self, Lexer, Token}; use cretonne::types::{Type, VOID, FunctionName, Signature, ArgumentType, ArgumentExtension}; @@ -249,7 +250,7 @@ impl<'a> Parser<'a> { // Match and consume a u8 immediate. // This is used for lane numbers in SIMD vectors. - fn match_u8(&mut self, err_msg: &str) -> Result { + fn match_uimm8(&mut self, err_msg: &str) -> Result { if let Some(Token::Integer(text)) = self.token() { self.consume(); // 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(&mut self, err_msg: &str) -> Result { + 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. /// /// This is the top-level parse function matching the whole contents of a file. @@ -847,7 +858,7 @@ impl<'a> Parser<'a> { InstructionFormat::InsertLane => { let lhs = try!(self.match_value("expected SSA value first operand")); 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")); let rhs = try!(self.match_value("expected SSA value last operand")); InstructionData::InsertLane { @@ -860,7 +871,7 @@ impl<'a> Parser<'a> { InstructionFormat::ExtractLane => { let arg = try!(self.match_value("expected SSA value last operand")); 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 { opcode: opcode, ty: VOID, @@ -868,6 +879,32 @@ impl<'a> Parser<'a> { 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::Call => { unimplemented!(); diff --git a/cranelift/tests/parser/tiny.cton b/cranelift/tests/parser/tiny.cton index 6be261e273..e404985bf8 100644 --- a/cranelift/tests/parser/tiny.cton +++ b/cranelift/tests/parser/tiny.cton @@ -26,3 +26,19 @@ ebb0: v1 = extractlane v0, 3 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 +} diff --git a/cranelift/tests/parser/tiny.cton.ref b/cranelift/tests/parser/tiny.cton.ref index 1fc1745a34..31f5767335 100644 --- a/cranelift/tests/parser/tiny.cton.ref +++ b/cranelift/tests/parser/tiny.cton.ref @@ -21,3 +21,17 @@ ebb0: v1 = extractlane v0, 3 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 +} diff --git a/meta/cretonne/base.py b/meta/cretonne/base.py index b41225ae00..e6d008585b 100644 --- a/meta/cretonne/base.py +++ b/meta/cretonne/base.py @@ -6,7 +6,7 @@ support. """ from . import TypeVar, Operand, Instruction, InstructionGroup, variable_args 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 instructions = InstructionGroup("base", "Shared base instruction set") @@ -217,6 +217,34 @@ extractlane = Instruction( # 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) x = Operand('x', Int) y = Operand('y', Int) @@ -515,4 +543,81 @@ popcnt = Instruction( """, 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() diff --git a/meta/cretonne/formats.py b/meta/cretonne/formats.py index 6f09c4b5af..62c678f9b9 100644 --- a/meta/cretonne/formats.py +++ b/meta/cretonne/formats.py @@ -8,7 +8,7 @@ in this module. 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 Nullary = InstructionFormat() @@ -33,6 +33,9 @@ Select = InstructionFormat(value, value, value, typevar_operand=1) InsertLane = InstructionFormat(value, uimm8, value) ExtractLane = InstructionFormat(value, uimm8) +IntCompare = InstructionFormat(intcc, value, value) +FloatCompare = InstructionFormat(floatcc, value, value) + 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/meta/cretonne/immediates.py b/meta/cretonne/immediates.py index 299b340bce..f20a6142d3 100644 --- a/meta/cretonne/immediates.py +++ b/meta/cretonne/immediates.py @@ -29,3 +29,16 @@ ieee64 = ImmediateKind('ieee64', 'A 64-bit immediate floating point number.') #: A large SIMD vector constant. 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.')