diff --git a/cranelift/filetests/parser/ternary.cton b/cranelift/filetests/parser/ternary.cton new file mode 100644 index 0000000000..5305126c49 --- /dev/null +++ b/cranelift/filetests/parser/ternary.cton @@ -0,0 +1,13 @@ +test cat +test verifier + +function add_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 { +ebb1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32): + v10, v11 = iadd_cout v1, v4 + ;check: $v10, $v11 = iadd_cout $v1, $v4 + v20, v21 = iadd_carry v2, v5, v11 + ; check: $v20, $v21 = iadd_carry $v2, $v5, $v11 + v30 = iadd_cin v3, v6, v21 + ; check: $v30 = iadd_cin $v3, $v6, $v21 + return v10, v20, v30 +} diff --git a/cranelift/src/libcretonne/ir/instructions.rs b/cranelift/src/libcretonne/ir/instructions.rs index c8228d1f43..bfc1fe65f3 100644 --- a/cranelift/src/libcretonne/ir/instructions.rs +++ b/cranelift/src/libcretonne/ir/instructions.rs @@ -149,6 +149,11 @@ pub enum InstructionData { ty: Type, args: [Value; 3], }, + TernaryOverflow { + opcode: Opcode, + ty: Type, + data: Box, + }, InsertLane { opcode: Opcode, ty: Type, @@ -254,6 +259,19 @@ impl Default for VariableArgs { } } +/// Payload data for ternary instructions with multiple results, such as `iadd_carry`. +#[derive(Clone, Debug)] +pub struct TernaryOverflowData { + pub second_result: Value, + pub args: [Value; 3], +} + +impl Display for TernaryOverflowData { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}, {}, {}", self.args[0], self.args[1], self.args[2]) + } +} + /// Payload data for jump instructions. These need to carry lists of EBB arguments that won't fit /// in the allowed InstructionData size. #[derive(Clone, Debug)] diff --git a/cranelift/src/libcretonne/write.rs b/cranelift/src/libcretonne/write.rs index bfdd13b32f..ea73d18666 100644 --- a/cranelift/src/libcretonne/write.rs +++ b/cranelift/src/libcretonne/write.rs @@ -190,6 +190,7 @@ fn write_instruction(w: &mut Write, 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), 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]), diff --git a/cranelift/src/libreader/parser.rs b/cranelift/src/libreader/parser.rs index 05fa9b831b..723cfb1951 100644 --- a/cranelift/src/libreader/parser.rs +++ b/cranelift/src/libreader/parser.rs @@ -13,8 +13,8 @@ use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotDa use cretonne::ir::types::{VOID, Signature, ArgumentType, ArgumentExtension}; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE}; -use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, JumpData, - BranchData, ReturnData}; +use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, + TernaryOverflowData, JumpData, BranchData, ReturnData}; use cretonne::isa; use cretonne::settings; use testfile::{TestFile, Details, Comment}; @@ -138,6 +138,10 @@ impl Context { try!(self.map.rewrite_values(args, loc)); } + InstructionData::TernaryOverflow { ref mut data, .. } => { + try!(self.map.rewrite_values(&mut data.args, loc)); + } + InstructionData::Jump { ref mut data, .. } => { try!(self.map.rewrite_ebb(&mut data.destination, loc)); try!(self.map.rewrite_values(&mut data.arguments, loc)); @@ -1066,6 +1070,22 @@ impl<'a> Parser<'a> { args: [ctrl_arg, true_arg, false_arg], } } + InstructionFormat::TernaryOverflow => { + // Names here refer to the `iadd_carry` instruction. + 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")); + try!(self.match_token(Token::Comma, "expected ',' between operands")); + let cin = try!(self.match_value("expected SSA value third operand")); + InstructionData::TernaryOverflow { + opcode: opcode, + ty: VOID, + data: Box::new(TernaryOverflowData { + second_result: NO_VALUE, + args: [lhs, rhs, cin], + }), + } + } InstructionFormat::Jump => { // Parse the destination EBB number. Don't translate source to local numbers yet. let ebb_num = try!(self.match_ebb("expected jump destination EBB")); diff --git a/meta/cretonne/base.py b/meta/cretonne/base.py index 30d890b076..f94668da4a 100644 --- a/meta/cretonne/base.py +++ b/meta/cretonne/base.py @@ -6,7 +6,7 @@ support. """ from __future__ import absolute_import from . import TypeVar, Operand, Instruction, InstructionGroup, variable_args -from .types import i8, f32, f64 +from .types import i8, f32, f64, b1 from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc from . import entities @@ -405,6 +405,48 @@ isub_imm = Instruction( """, ins=(X, y), outs=a) +# +# Integer arithmetic with carry. +# +a = Operand('a', iB) +x = Operand('x', iB) +y = Operand('y', iB) +cin = Operand('cin', b1, doc="Input carry flag") +cout = Operand('cout', b1, doc="Output carry flag") + +iadd_cin = Instruction( + 'iadd_cin', """ + Add integers with carry in. + + Same as :inst:`iadd` with an additional carry input. + + Polymorphic over all scalar integer types, but does not support vector + types. + """, + ins=(x, y, cin), outs=a) + +iadd_cout = Instruction( + 'iadd_cout', """ + Add integers with carry out. + + Same as :inst:`iadd` with an additional carry output. + + Polymorphic over all scalar integer types, but does not support vector + types. + """, + ins=(x, y), outs=(a, cout)) + +iadd_carry = Instruction( + 'iadd_carry', """ + Add integers with carry in and out. + + Same as :inst:`iadd` with an additional carry output. + + Polymorphic over all scalar integer types, but does not support vector + types. + """, + ins=(x, y, cin), outs=(a, cout)) + # # Bitwise operations. # diff --git a/meta/cretonne/formats.py b/meta/cretonne/formats.py index 06f4593086..48b9d978af 100644 --- a/meta/cretonne/formats.py +++ b/meta/cretonne/formats.py @@ -30,6 +30,10 @@ BinaryOverflow = InstructionFormat(value, value, multiple_results=True) # The fma instruction has the same constraint on all inputs. Ternary = InstructionFormat(value, value, value, typevar_operand=1) +# Carry in *and* carry out for `iadd_carry` and friends. +TernaryOverflow = InstructionFormat( + value, value, value, multiple_results=True, boxed_storage=True) + InsertLane = InstructionFormat(value, ('lane', uimm8), value) ExtractLane = InstructionFormat(value, ('lane', uimm8)) diff --git a/meta/gen_instr.py b/meta/gen_instr.py index 139acf59b7..6c67077cb0 100644 --- a/meta/gen_instr.py +++ b/meta/gen_instr.py @@ -153,9 +153,8 @@ def gen_instruction_data_impl(fmt): if f.boxed_storage: fmt.line( n + - ' {{ ref data, .. }} => ' + - 'Some(data.args[{}]),' - .format(i)) + ' { ref data, .. } => ' + + ('Some(data.args[{}]),'.format(i))) else: fmt.line( n +