Integer add with carry instructions.

Integer addition with carry in/out/both.
This commit is contained in:
Jakob Stoklund Olesen
2016-09-23 13:32:26 -07:00
parent acf41a7c09
commit b1bd3140db
7 changed files with 103 additions and 6 deletions

View File

@@ -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
}

View File

@@ -149,6 +149,11 @@ pub enum InstructionData {
ty: Type, ty: Type,
args: [Value; 3], args: [Value; 3],
}, },
TernaryOverflow {
opcode: Opcode,
ty: Type,
data: Box<TernaryOverflowData>,
},
InsertLane { InsertLane {
opcode: Opcode, opcode: Opcode,
ty: Type, 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 /// Payload data for jump instructions. These need to carry lists of EBB arguments that won't fit
/// in the allowed InstructionData size. /// in the allowed InstructionData size.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@@ -190,6 +190,7 @@ fn write_instruction(w: &mut Write,
BinaryImmRev { imm, arg, .. } => writeln!(w, " {}, {}", imm, arg), 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),
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]), IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),

View File

@@ -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::types::{VOID, Signature, ArgumentType, ArgumentExtension};
use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64};
use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE}; use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE};
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, JumpData, use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs,
BranchData, ReturnData}; TernaryOverflowData, JumpData, BranchData, ReturnData};
use cretonne::isa; use cretonne::isa;
use cretonne::settings; use cretonne::settings;
use testfile::{TestFile, Details, Comment}; use testfile::{TestFile, Details, Comment};
@@ -138,6 +138,10 @@ impl Context {
try!(self.map.rewrite_values(args, loc)); 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, .. } => { InstructionData::Jump { ref mut data, .. } => {
try!(self.map.rewrite_ebb(&mut data.destination, loc)); try!(self.map.rewrite_ebb(&mut data.destination, loc));
try!(self.map.rewrite_values(&mut data.arguments, 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], 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 => { InstructionFormat::Jump => {
// Parse the destination EBB number. Don't translate source to local numbers yet. // Parse the destination EBB number. Don't translate source to local numbers yet.
let ebb_num = try!(self.match_ebb("expected jump destination EBB")); let ebb_num = try!(self.match_ebb("expected jump destination EBB"));

View File

@@ -6,7 +6,7 @@ support.
""" """
from __future__ import absolute_import from __future__ import absolute_import
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, b1
from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc
from . import entities from . import entities
@@ -405,6 +405,48 @@ isub_imm = Instruction(
""", """,
ins=(X, y), outs=a) 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. # Bitwise operations.
# #

View File

@@ -30,6 +30,10 @@ BinaryOverflow = InstructionFormat(value, value, multiple_results=True)
# The fma instruction has the same constraint on all inputs. # The fma instruction has the same constraint on all inputs.
Ternary = InstructionFormat(value, value, value, typevar_operand=1) 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) InsertLane = InstructionFormat(value, ('lane', uimm8), value)
ExtractLane = InstructionFormat(value, ('lane', uimm8)) ExtractLane = InstructionFormat(value, ('lane', uimm8))

View File

@@ -153,9 +153,8 @@ def gen_instruction_data_impl(fmt):
if f.boxed_storage: if f.boxed_storage:
fmt.line( fmt.line(
n + n +
' {{ ref data, .. }} => ' + ' { ref data, .. } => ' +
'Some(data.args[{}]),' ('Some(data.args[{}]),'.format(i)))
.format(i))
else: else:
fmt.line( fmt.line(
n + n +