Integer add with carry instructions.
Integer addition with carry in/out/both.
This commit is contained in:
13
cranelift/filetests/parser/ternary.cton
Normal file
13
cranelift/filetests/parser/ternary.cton
Normal 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
|
||||||
|
}
|
||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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]),
|
||||||
|
|||||||
@@ -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"));
|
||||||
|
|||||||
@@ -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.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|
||||||
|
|||||||
@@ -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 +
|
||||||
|
|||||||
Reference in New Issue
Block a user