[codegen] reintroduce support for carry and borrow instructions in RI… (#1005)

Reintroduce support for iadd carry variants and isub borrow variants for
RISC ISAs which had been removed in
https://github.com/CraneStation/cranelift/pull/961 and
https://github.com/CraneStation/cranelift/pull/962 because of the lack
of a proper flags register in RISC architectures.
This commit is contained in:
Ujjwal Sharma
2019-09-13 20:57:50 +05:30
committed by Benjamin Bouvier
parent cadd0ac655
commit 3418fb6e18
17 changed files with 326 additions and 85 deletions

View File

@@ -66,9 +66,9 @@ pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let mut t32 = CpuMode::new("T32"); let mut t32 = CpuMode::new("T32");
// TODO refine these. // TODO refine these.
let narrow = shared_defs.transform_groups.by_name("narrow"); let narrow_flags = shared_defs.transform_groups.by_name("narrow_flags");
a32.legalize_default(narrow); a32.legalize_default(narrow_flags);
t32.legalize_default(narrow); t32.legalize_default(narrow_flags);
let cpu_modes = vec![a32, t32]; let cpu_modes = vec![a32, t32];

View File

@@ -60,8 +60,8 @@ pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let mut a64 = CpuMode::new("A64"); let mut a64 = CpuMode::new("A64");
// TODO refine these. // TODO refine these.
let narrow = shared_defs.transform_groups.by_name("narrow"); let narrow_flags = shared_defs.transform_groups.by_name("narrow_flags");
a64.legalize_default(narrow); a64.legalize_default(narrow_flags);
let cpu_modes = vec![a64]; let cpu_modes = vec![a64];

View File

@@ -102,15 +102,16 @@ pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let mut rv_64 = CpuMode::new("RV64"); let mut rv_64 = CpuMode::new("RV64");
let expand = shared_defs.transform_groups.by_name("expand"); let expand = shared_defs.transform_groups.by_name("expand");
let narrow = shared_defs.transform_groups.by_name("narrow"); let narrow_no_flags = shared_defs.transform_groups.by_name("narrow_no_flags");
rv_32.legalize_monomorphic(expand); rv_32.legalize_monomorphic(expand);
rv_32.legalize_default(narrow); rv_32.legalize_default(narrow_no_flags);
rv_32.legalize_type(I32, expand); rv_32.legalize_type(I32, expand);
rv_32.legalize_type(F32, expand); rv_32.legalize_type(F32, expand);
rv_32.legalize_type(F64, expand); rv_32.legalize_type(F64, expand);
rv_64.legalize_monomorphic(expand); rv_64.legalize_monomorphic(expand);
rv_64.legalize_default(narrow); rv_64.legalize_default(narrow_no_flags);
rv_64.legalize_type(I32, expand); rv_64.legalize_type(I32, expand);
rv_64.legalize_type(I64, expand); rv_64.legalize_type(I64, expand);
rv_64.legalize_type(F32, expand); rv_64.legalize_type(F32, expand);

View File

@@ -384,9 +384,9 @@ pub(crate) fn define(
let func_addr = shared.by_name("func_addr"); let func_addr = shared.by_name("func_addr");
let get_pinned_reg = shared.by_name("get_pinned_reg"); let get_pinned_reg = shared.by_name("get_pinned_reg");
let iadd = shared.by_name("iadd"); let iadd = shared.by_name("iadd");
let iadd_cout = shared.by_name("iadd_cout"); let iadd_ifcout = shared.by_name("iadd_ifcout");
let iadd_cin = shared.by_name("iadd_cin"); let iadd_ifcin = shared.by_name("iadd_ifcin");
let iadd_carry = shared.by_name("iadd_carry"); let iadd_ifcarry = shared.by_name("iadd_ifcarry");
let iadd_imm = shared.by_name("iadd_imm"); let iadd_imm = shared.by_name("iadd_imm");
let icmp = shared.by_name("icmp"); let icmp = shared.by_name("icmp");
let icmp_imm = shared.by_name("icmp_imm"); let icmp_imm = shared.by_name("icmp_imm");
@@ -407,9 +407,9 @@ pub(crate) fn define(
let istore8 = shared.by_name("istore8"); let istore8 = shared.by_name("istore8");
let istore8_complex = shared.by_name("istore8_complex"); let istore8_complex = shared.by_name("istore8_complex");
let isub = shared.by_name("isub"); let isub = shared.by_name("isub");
let isub_bout = shared.by_name("isub_bout"); let isub_ifbout = shared.by_name("isub_ifbout");
let isub_bin = shared.by_name("isub_bin"); let isub_ifbin = shared.by_name("isub_ifbin");
let isub_borrow = shared.by_name("isub_borrow"); let isub_ifborrow = shared.by_name("isub_ifborrow");
let jump = shared.by_name("jump"); let jump = shared.by_name("jump");
let jump_table_base = shared.by_name("jump_table_base"); let jump_table_base = shared.by_name("jump_table_base");
let jump_table_entry = shared.by_name("jump_table_entry"); let jump_table_entry = shared.by_name("jump_table_entry");
@@ -647,14 +647,14 @@ pub(crate) fn define(
); );
e.enc_i32_i64(iadd, rec_rr.opcodes(vec![0x01])); e.enc_i32_i64(iadd, rec_rr.opcodes(vec![0x01]));
e.enc_i32_i64(iadd_cout, rec_rout.opcodes(vec![0x01])); e.enc_i32_i64(iadd_ifcout, rec_rout.opcodes(vec![0x01]));
e.enc_i32_i64(iadd_cin, rec_rin.opcodes(vec![0x11])); e.enc_i32_i64(iadd_ifcin, rec_rin.opcodes(vec![0x11]));
e.enc_i32_i64(iadd_carry, rec_rio.opcodes(vec![0x11])); e.enc_i32_i64(iadd_ifcarry, rec_rio.opcodes(vec![0x11]));
e.enc_i32_i64(isub, rec_rr.opcodes(vec![0x29])); e.enc_i32_i64(isub, rec_rr.opcodes(vec![0x29]));
e.enc_i32_i64(isub_bout, rec_rout.opcodes(vec![0x29])); e.enc_i32_i64(isub_ifbout, rec_rout.opcodes(vec![0x29]));
e.enc_i32_i64(isub_bin, rec_rin.opcodes(vec![0x19])); e.enc_i32_i64(isub_ifbin, rec_rin.opcodes(vec![0x19]));
e.enc_i32_i64(isub_borrow, rec_rio.opcodes(vec![0x19])); e.enc_i32_i64(isub_ifborrow, rec_rio.opcodes(vec![0x19]));
e.enc_i32_i64(band, rec_rr.opcodes(vec![0x21])); e.enc_i32_i64(band, rec_rr.opcodes(vec![0x21]));
e.enc_i32_i64(bor, rec_rr.opcodes(vec![0x09])); e.enc_i32_i64(bor, rec_rr.opcodes(vec![0x09]));

View File

@@ -305,7 +305,7 @@ pub(crate) fn define(shared: &mut SharedDefinitions, x86_instructions: &Instruct
Use x86-specific instructions if needed."#, Use x86-specific instructions if needed."#,
) )
.isa("x86") .isa("x86")
.chain_with(shared.transform_groups.by_name("narrow").id); .chain_with(shared.transform_groups.by_name("narrow_flags").id);
// SIMD // SIMD
let uimm8_zero = Literal::constant(&imm.uimm8, 0x00); let uimm8_zero = Literal::constant(&imm.uimm8, 0x00);

View File

@@ -29,13 +29,13 @@ pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let mut x86_32 = CpuMode::new("I32"); let mut x86_32 = CpuMode::new("I32");
let expand_flags = shared_defs.transform_groups.by_name("expand_flags"); let expand_flags = shared_defs.transform_groups.by_name("expand_flags");
let narrow = shared_defs.transform_groups.by_name("narrow"); let narrow_flags = shared_defs.transform_groups.by_name("narrow_flags");
let widen = shared_defs.transform_groups.by_name("widen"); let widen = shared_defs.transform_groups.by_name("widen");
let x86_narrow = shared_defs.transform_groups.by_name("x86_narrow"); let x86_narrow = shared_defs.transform_groups.by_name("x86_narrow");
let x86_expand = shared_defs.transform_groups.by_name("x86_expand"); let x86_expand = shared_defs.transform_groups.by_name("x86_expand");
x86_32.legalize_monomorphic(expand_flags); x86_32.legalize_monomorphic(expand_flags);
x86_32.legalize_default(narrow); x86_32.legalize_default(narrow_flags);
x86_32.legalize_type(B1, expand_flags); x86_32.legalize_type(B1, expand_flags);
x86_32.legalize_type(I8, widen); x86_32.legalize_type(I8, widen);
x86_32.legalize_type(I16, widen); x86_32.legalize_type(I16, widen);

View File

@@ -1879,10 +1879,16 @@ pub(crate) fn define(
let a = &operand("a", iB); let a = &operand("a", iB);
let x = &operand("x", iB); let x = &operand("x", iB);
let y = &operand("y", iB); let y = &operand("y", iB);
let c_in = &operand_doc("c_in", iflags, "Input carry flag");
let c_out = &operand_doc("c_out", iflags, "Output carry flag"); let c_in = &operand_doc("c_in", b1, "Input carry flag");
let b_in = &operand_doc("b_in", iflags, "Input borrow flag"); let c_out = &operand_doc("c_out", b1, "Output carry flag");
let b_out = &operand_doc("b_out", iflags, "Output borrow flag"); let b_in = &operand_doc("b_in", b1, "Input borrow flag");
let b_out = &operand_doc("b_out", b1, "Output borrow flag");
let c_if_in = &operand("c_in", iflags);
let c_if_out = &operand("c_out", iflags);
let b_if_in = &operand("b_in", iflags);
let b_if_out = &operand("b_out", iflags);
ig.push( ig.push(
Inst::new( Inst::new(
@@ -1904,6 +1910,26 @@ pub(crate) fn define(
.operands_out(vec![a]), .operands_out(vec![a]),
); );
ig.push(
Inst::new(
"iadd_ifcin",
r#"
Add integers with carry in.
Same as `iadd` with an additional carry flag input. Computes:
```text
a = x + y + c_{in} \pmod 2^B
```
Polymorphic over all scalar integer types, but does not support vector
types.
"#,
)
.operands_in(vec![x, y, c_if_in])
.operands_out(vec![a]),
);
ig.push( ig.push(
Inst::new( Inst::new(
"iadd_cout", "iadd_cout",
@@ -1925,6 +1951,27 @@ pub(crate) fn define(
.operands_out(vec![a, c_out]), .operands_out(vec![a, c_out]),
); );
ig.push(
Inst::new(
"iadd_ifcout",
r#"
Add integers with carry out.
Same as `iadd` with an additional carry flag output.
```text
a &= x + y \pmod 2^B \\
c_{out} &= x+y >= 2^B
```
Polymorphic over all scalar integer types, but does not support vector
types.
"#,
)
.operands_in(vec![x, y])
.operands_out(vec![a, c_if_out]),
);
ig.push( ig.push(
Inst::new( Inst::new(
"iadd_carry", "iadd_carry",
@@ -1946,6 +1993,27 @@ pub(crate) fn define(
.operands_out(vec![a, c_out]), .operands_out(vec![a, c_out]),
); );
ig.push(
Inst::new(
"iadd_ifcarry",
r#"
Add integers with carry in and out.
Same as `iadd` with an additional carry flag input and output.
```text
a &= x + y + c_{in} \pmod 2^B \\
c_{out} &= x + y + c_{in} >= 2^B
```
Polymorphic over all scalar integer types, but does not support vector
types.
"#,
)
.operands_in(vec![x, y, c_if_in])
.operands_out(vec![a, c_if_out]),
);
ig.push( ig.push(
Inst::new( Inst::new(
"isub_bin", "isub_bin",
@@ -1966,6 +2034,26 @@ pub(crate) fn define(
.operands_out(vec![a]), .operands_out(vec![a]),
); );
ig.push(
Inst::new(
"isub_ifbin",
r#"
Subtract integers with borrow in.
Same as `isub` with an additional borrow flag input. Computes:
```text
a = x - (y + b_{in}) \pmod 2^B
```
Polymorphic over all scalar integer types, but does not support vector
types.
"#,
)
.operands_in(vec![x, y, b_if_in])
.operands_out(vec![a]),
);
ig.push( ig.push(
Inst::new( Inst::new(
"isub_bout", "isub_bout",
@@ -1987,6 +2075,27 @@ pub(crate) fn define(
.operands_out(vec![a, b_out]), .operands_out(vec![a, b_out]),
); );
ig.push(
Inst::new(
"isub_ifbout",
r#"
Subtract integers with borrow out.
Same as `isub` with an additional borrow flag output.
```text
a &= x - y \pmod 2^B \\
b_{out} &= x < y
```
Polymorphic over all scalar integer types, but does not support vector
types.
"#,
)
.operands_in(vec![x, y])
.operands_out(vec![a, b_if_out]),
);
ig.push( ig.push(
Inst::new( Inst::new(
"isub_borrow", "isub_borrow",
@@ -2008,6 +2117,27 @@ pub(crate) fn define(
.operands_out(vec![a, b_out]), .operands_out(vec![a, b_out]),
); );
ig.push(
Inst::new(
"isub_ifborrow",
r#"
Subtract integers with borrow in and out.
Same as `isub` with an additional borrow flag input and output.
```text
a &= x - (y + b_{in}) \pmod 2^B \\
b_{out} &= x < y + b_{in}
```
Polymorphic over all scalar integer types, but does not support vector
types.
"#,
)
.operands_in(vec![x, y, b_if_in])
.operands_out(vec![a, b_if_out]),
);
let bits = &TypeVar::new( let bits = &TypeVar::new(
"bits", "bits",
"Any integer, float, or boolean scalar or vector type", "Any integer, float, or boolean scalar or vector type",

View File

@@ -69,6 +69,9 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
let iadd = insts.by_name("iadd"); let iadd = insts.by_name("iadd");
let iadd_cin = insts.by_name("iadd_cin"); let iadd_cin = insts.by_name("iadd_cin");
let iadd_cout = insts.by_name("iadd_cout"); let iadd_cout = insts.by_name("iadd_cout");
let iadd_carry = insts.by_name("iadd_carry");
let iadd_ifcin = insts.by_name("iadd_ifcin");
let iadd_ifcout = insts.by_name("iadd_ifcout");
let iadd_imm = insts.by_name("iadd_imm"); let iadd_imm = insts.by_name("iadd_imm");
let icmp = insts.by_name("icmp"); let icmp = insts.by_name("icmp");
let icmp_imm = insts.by_name("icmp_imm"); let icmp_imm = insts.by_name("icmp_imm");
@@ -88,6 +91,9 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
let isub = insts.by_name("isub"); let isub = insts.by_name("isub");
let isub_bin = insts.by_name("isub_bin"); let isub_bin = insts.by_name("isub_bin");
let isub_bout = insts.by_name("isub_bout"); let isub_bout = insts.by_name("isub_bout");
let isub_borrow = insts.by_name("isub_borrow");
let isub_ifbin = insts.by_name("isub_ifbin");
let isub_ifbout = insts.by_name("isub_ifbout");
let load = insts.by_name("load"); let load = insts.by_name("load");
let popcnt = insts.by_name("popcnt"); let popcnt = insts.by_name("popcnt");
let rotl = insts.by_name("rotl"); let rotl = insts.by_name("rotl");
@@ -154,11 +160,15 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
let b2 = var("b2"); let b2 = var("b2");
let b3 = var("b3"); let b3 = var("b3");
let b4 = var("b4"); let b4 = var("b4");
let b_in = var("b_in");
let b_int = var("b_int");
let c = var("c"); let c = var("c");
let c1 = var("c1"); let c1 = var("c1");
let c2 = var("c2"); let c2 = var("c2");
let c3 = var("c3"); let c3 = var("c3");
let c4 = var("c4"); let c4 = var("c4");
let c_in = var("c_in");
let c_int = var("c_int");
let d = var("d"); let d = var("d");
let d1 = var("d1"); let d1 = var("d1");
let d2 = var("d2"); let d2 = var("d2");
@@ -192,28 +202,6 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
// embedded as part of arguments), so use a custom legalization for now. // embedded as part of arguments), so use a custom legalization for now.
narrow.custom_legalize(iconst, "narrow_iconst"); narrow.custom_legalize(iconst, "narrow_iconst");
narrow.legalize(
def!(a = iadd(x, y)),
vec![
def!((xl, xh) = isplit(x)),
def!((yl, yh) = isplit(y)),
def!((al, c) = iadd_cout(xl, yl)),
def!(ah = iadd_cin(xh, yh, c)),
def!(a = iconcat(al, ah)),
],
);
narrow.legalize(
def!(a = isub(x, y)),
vec![
def!((xl, xh) = isplit(x)),
def!((yl, yh) = isplit(y)),
def!((al, b) = isub_bout(xl, yl)),
def!(ah = isub_bin(xh, yh, b)),
def!(a = iconcat(al, ah)),
],
);
for &bin_op in &[band, bor, bxor, band_not, bor_not, bxor_not] { for &bin_op in &[band, bor, bxor, band_not, bor_not, bxor_not] {
narrow.legalize( narrow.legalize(
def!(a = bin_op(x, y)), def!(a = bin_op(x, y)),
@@ -502,6 +490,58 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
} }
} }
// Expand integer operations with carry for RISC architectures that don't have
// the flags.
let intcc_ult = Literal::enumerator_for(&imm.intcc, "ult");
expand.legalize(
def!((a, c) = iadd_cout(x, y)),
vec![def!(a = iadd(x, y)), def!(c = icmp(intcc_ult, a, x))],
);
let intcc_ugt = Literal::enumerator_for(&imm.intcc, "ugt");
expand.legalize(
def!((a, b) = isub_bout(x, y)),
vec![def!(a = isub(x, y)), def!(b = icmp(intcc_ugt, a, x))],
);
expand.legalize(
def!(a = iadd_cin(x, y, c)),
vec![
def!(a1 = iadd(x, y)),
def!(c_int = bint(c)),
def!(a = iadd(a1, c_int)),
],
);
expand.legalize(
def!(a = isub_bin(x, y, b)),
vec![
def!(a1 = isub(x, y)),
def!(b_int = bint(b)),
def!(a = isub(a1, b_int)),
],
);
expand.legalize(
def!((a, c) = iadd_carry(x, y, c_in)),
vec![
def!((a1, c1) = iadd_cout(x, y)),
def!(c_int = bint(c_in)),
def!((a, c2) = iadd_cout(a1, c_int)),
def!(c = bor(c1, c2)),
],
);
expand.legalize(
def!((a, b) = isub_borrow(x, y, b_in)),
vec![
def!((a1, b1) = isub_bout(x, y)),
def!(b_int = bint(b_in)),
def!((a, b2) = isub_bout(a1, b_int)),
def!(b = bor(b1, b2)),
],
);
// Expansions for fcvt_from_{u,s}int for smaller integer types. // Expansions for fcvt_from_{u,s}int for smaller integer types.
// These use expand and not widen because the controlling type variable for // These use expand and not widen because the controlling type variable for
// these instructions are f32/f64, which are legalized as part of the expand // these instructions are f32/f64, which are legalized as part of the expand
@@ -758,7 +798,7 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
let mut groups = TransformGroups::new(); let mut groups = TransformGroups::new();
narrow.build_and_add_to(&mut groups); let narrow_id = narrow.build_and_add_to(&mut groups);
let expand_id = expand.build_and_add_to(&mut groups); let expand_id = expand.build_and_add_to(&mut groups);
// Expansions using CPU flags. // Expansions using CPU flags.
@@ -796,6 +836,82 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro
expand_flags.build_and_add_to(&mut groups); expand_flags.build_and_add_to(&mut groups);
// Narrow legalizations using CPU flags.
let mut narrow_flags = TransformGroupBuilder::new(
"narrow_flags",
r#"
Narrow instructions for architectures with flags.
Narrow some instructions using CPU flags, then fall back to the normal
legalizations. Not all architectures support CPU flags, so these
patterns are kept separate.
"#,
)
.chain_with(narrow_id);
narrow_flags.legalize(
def!(a = iadd(x, y)),
vec![
def!((xl, xh) = isplit(x)),
def!((yl, yh) = isplit(y)),
def!((al, c) = iadd_ifcout(xl, yl)),
def!(ah = iadd_ifcin(xh, yh, c)),
def!(a = iconcat(al, ah)),
],
);
narrow_flags.legalize(
def!(a = isub(x, y)),
vec![
def!((xl, xh) = isplit(x)),
def!((yl, yh) = isplit(y)),
def!((al, b) = isub_ifbout(xl, yl)),
def!(ah = isub_ifbin(xh, yh, b)),
def!(a = iconcat(al, ah)),
],
);
narrow_flags.build_and_add_to(&mut groups);
// TODO(ryzokuken): figure out a way to legalize iadd_c* to iadd_ifc* (and
// similarly isub_b* to isub_ifb*) on expand_flags so that this isn't required.
// Narrow legalizations for ISAs that don't have CPU flags.
let mut narrow_no_flags = TransformGroupBuilder::new(
"narrow_no_flags",
r#"
Narrow instructions for architectures without flags.
Narrow some instructions avoiding the use of CPU flags, then fall back
to the normal legalizations. Not all architectures support CPU flags,
so these patterns are kept separate.
"#,
)
.chain_with(narrow_id);
narrow_no_flags.legalize(
def!(a = iadd(x, y)),
vec![
def!((xl, xh) = isplit(x)),
def!((yl, yh) = isplit(y)),
def!((al, c) = iadd_cout(xl, yl)),
def!(ah = iadd_cin(xh, yh, c)),
def!(a = iconcat(al, ah)),
],
);
narrow_no_flags.legalize(
def!(a = isub(x, y)),
vec![
def!((xl, xh) = isplit(x)),
def!((yl, yh) = isplit(y)),
def!((al, b) = isub_bout(xl, yl)),
def!(ah = isub_bin(xh, yh, b)),
def!(a = iconcat(al, ah)),
],
);
narrow_no_flags.build_and_add_to(&mut groups);
// TODO The order of declarations unfortunately matters to be compatible with the Python code. // TODO The order of declarations unfortunately matters to be compatible with the Python code.
// When it's all migrated, we can put this next to the narrow/expand build_and_add_to calls // When it's all migrated, we can put this next to the narrow/expand build_and_add_to calls
// above. // above.

View File

@@ -1253,7 +1253,7 @@ mod tests {
assert_eq!(pos.func.dfg.resolve_aliases(v1), v1); assert_eq!(pos.func.dfg.resolve_aliases(v1), v1);
let arg0 = pos.func.dfg.append_ebb_param(ebb0, types::I32); let arg0 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
let (s, c) = pos.ins().iadd_cout(v1, arg0); let (s, c) = pos.ins().iadd_ifcout(v1, arg0);
let iadd = match pos.func.dfg.value_def(s) { let iadd = match pos.func.dfg.value_def(s) {
ValueDef::Result(i, 0) => i, ValueDef::Result(i, 0) => i,
_ => panic!(), _ => panic!(),
@@ -1263,7 +1263,7 @@ mod tests {
pos.func.dfg.clear_results(iadd); pos.func.dfg.clear_results(iadd);
pos.func.dfg.attach_result(iadd, s); pos.func.dfg.attach_result(iadd, s);
// Replace `iadd_cout` with a normal `iadd` and an `ifcmp`. // Replace `iadd_ifcout` with a normal `iadd` and an `ifcmp`.
pos.func.dfg.replace(iadd).iadd(v1, arg0); pos.func.dfg.replace(iadd).iadd(v1, arg0);
let c2 = pos.ins().ifcmp(s, v1); let c2 = pos.ins().ifcmp(s, v1);
pos.func.dfg.change_to_alias(c, c2); pos.func.dfg.change_to_alias(c, c2);

View File

@@ -82,7 +82,7 @@ fn dynamic_addr(
} else { } else {
// We need an overflow check for the adjusted offset. // We need an overflow check for the adjusted offset.
let access_size_val = pos.ins().iconst(offset_ty, access_size as i64); let access_size_val = pos.ins().iconst(offset_ty, access_size as i64);
let (adj_offset, overflow) = pos.ins().iadd_cout(offset, access_size_val); let (adj_offset, overflow) = pos.ins().iadd_ifcout(offset, access_size_val);
pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds); pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
oob = pos oob = pos
.ins() .ins()

View File

@@ -1,6 +1,3 @@
; TODO(ryzokuken): figure out a better legalization strategy for platforms that
; platforms that don't have flags.
; Test the legalization of i32 instructions that don't have RISC-V versions. ; Test the legalization of i32 instructions that don't have RISC-V versions.
test legalizer test legalizer

View File

@@ -1,6 +1,3 @@
; TODO(ryzokuken): figure out a better legalization strategy for platforms that
; platforms that don't have flags.
; Test the legalization of i64 arithmetic instructions. ; Test the legalization of i64 arithmetic instructions.
test legalizer test legalizer
target riscv32 supports_m=1 target riscv32 supports_m=1

View File

@@ -471,19 +471,19 @@ ebb0:
; Carry Addition ; Carry Addition
; asm: addl %esi, %ecx ; asm: addl %esi, %ecx
[-,%rcx,%rflags] v701, v702 = iadd_cout v1, v2 ; bin: 01 f1 [-,%rcx,%rflags] v701, v702 = iadd_ifcout v1, v2 ; bin: 01 f1
; asm: adcl %esi, %ecx ; asm: adcl %esi, %ecx
[-,%rcx] v703 = iadd_cin v1, v2, v702 ; bin: 11 f1 [-,%rcx] v703 = iadd_ifcin v1, v2, v702 ; bin: 11 f1
; asm: adcl %esi, %ecx ; asm: adcl %esi, %ecx
[-,%rcx,%rflags] v704, v705 = iadd_carry v1, v2, v702 ; bin: 11 f1 [-,%rcx,%rflags] v704, v705 = iadd_ifcarry v1, v2, v702 ; bin: 11 f1
; Borrow Subtraction ; Borrow Subtraction
; asm: subl %esi, %ecx ; asm: subl %esi, %ecx
[-,%rcx,%rflags] v706, v707 = isub_bout v1, v2 ; bin: 29 f1 [-,%rcx,%rflags] v706, v707 = isub_ifbout v1, v2 ; bin: 29 f1
; asm: sbbl %esi, %ecx ; asm: sbbl %esi, %ecx
[-,%rcx] v708 = isub_bin v1, v2, v707 ; bin: 19 f1 [-,%rcx] v708 = isub_ifbin v1, v2, v707 ; bin: 19 f1
; asm: sbbl %esi, %ecx ; asm: sbbl %esi, %ecx
[-,%rcx,%rflags] v709, v710 = isub_borrow v1, v2, v707 ; bin: 19 f1 [-,%rcx,%rflags] v709, v710 = isub_ifborrow v1, v2, v707 ; bin: 19 f1
; asm: testl %ecx, %ecx ; asm: testl %ecx, %ecx
; asm: je ebb1 ; asm: je ebb1

View File

@@ -9,8 +9,8 @@ ebb0(v1: i64, v2: i64):
v10 = iadd v1, v2 v10 = iadd v1, v2
; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V)
; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V)
; nextln: $(v10_lsb=$V), $(carry=$V) = iadd_cout $v1_lsb, $v2_lsb ; nextln: $(v10_lsb=$V), $(carry=$V) = iadd_ifcout $v1_lsb, $v2_lsb
; nextln: $(v10_msb=$V) = iadd_cin $v1_msb, $v2_msb, $carry ; nextln: $(v10_msb=$V) = iadd_ifcin $v1_msb, $v2_msb, $carry
; nextln: v10 = iconcat $v10_lsb, $v10_msb ; nextln: v10 = iconcat $v10_lsb, $v10_msb
return v10 return v10
} }
@@ -20,8 +20,8 @@ ebb0(v1: i64, v2: i64):
v10 = isub v1, v2 v10 = isub v1, v2
; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V)
; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V)
; nextln: $(v10_lsb=$V), $(borrow=$V) = isub_bout $v1_lsb, $v2_lsb ; nextln: $(v10_lsb=$V), $(borrow=$V) = isub_ifbout $v1_lsb, $v2_lsb
; nextln: $(v10_msb=$V) = isub_bin $v1_msb, $v2_msb, $borrow ; nextln: $(v10_msb=$V) = isub_ifbin $v1_msb, $v2_msb, $borrow
; nextln: v10 = iconcat $v10_lsb, $v10_msb ; nextln: v10 = iconcat $v10_lsb, $v10_msb
return v10 return v10
} }

View File

@@ -5,13 +5,13 @@ target i686 haswell
function %iadd(i64, i64) -> i64 { function %iadd(i64, i64) -> i64 {
ebb0(v1: i64, v2: i64): ebb0(v1: i64, v2: i64):
v10 = iadd v1, v2 v10 = iadd v1, v2
; check: iadd_cout ; check: iadd_ifcout
return v10 return v10
} }
function %isub(i64, i64) -> i64 { function %isub(i64, i64) -> i64 {
ebb0(v1: i64, v2: i64): ebb0(v1: i64, v2: i64):
v10 = isub v1, v2 v10 = isub v1, v2
; check: isub_bout ; check: isub_ifbout
return v10 return v10
} }

View File

@@ -8,7 +8,7 @@ function %foo(i32, i32) {
ebb1(v0: i32 [%x8], v1: i32): ebb1(v0: i32 [%x8], v1: i32):
[-,-] v2 = iadd v0, v1 [-,-] v2 = iadd v0, v1
[-] trap heap_oob [-] trap heap_oob
[R#1234, %x5, %x11] v6, v7 = iadd_cout v2, v0 [R#1234, %x5, %x11] v6, v7 = iadd_ifcout v2, v0
[Rshamt#beef, %x25] v8 = ishl_imm v6, 2 [Rshamt#beef, %x25] v8 = ishl_imm v6, 2
@55 v9 = iadd v8, v7 @55 v9 = iadd v8, v7
@a5 [Iret#5] return v0, v8 @a5 [Iret#5] return v0, v8
@@ -17,7 +17,7 @@ ebb1(v0: i32 [%x8], v1: i32):
; nextln: ebb1(v0: i32 [%x8], v1: i32): ; nextln: ebb1(v0: i32 [%x8], v1: i32):
; nextln: [-,-]$WS v2 = iadd v0, v1 ; nextln: [-,-]$WS v2 = iadd v0, v1
; nextln: [-]$WS trap heap_oob ; nextln: [-]$WS trap heap_oob
; nextln: [R#1234,%x5,%x11]$WS v6, v7 = iadd_cout v2, v0 ; nextln: [R#1234,%x5,%x11]$WS v6, v7 = iadd_ifcout v2, v0
; nextln: [Rshamt#beef,%x25]$WS v8 = ishl_imm v6, 2 ; nextln: [Rshamt#beef,%x25]$WS v8 = ishl_imm v6, 2
; nextln: @0055 [-,-]$WS v9 = iadd v8, v7 ; nextln: @0055 [-,-]$WS v9 = iadd v8, v7
; nextln: @00a5 [Iret#05]$WS return v0, v8 ; nextln: @00a5 [Iret#05]$WS return v0, v8

View File

@@ -3,22 +3,22 @@ test verifier
function %add_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 { 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): ebb1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32):
v10, v11 = iadd_cout v1, v4 v10, v11 = iadd_ifcout v1, v4
;check: v10, v11 = iadd_cout v1, v4 ;check: v10, v11 = iadd_ifcout v1, v4
v20, v21 = iadd_carry v2, v5, v11 v20, v21 = iadd_ifcarry v2, v5, v11
; check: v20, v21 = iadd_carry v2, v5, v11 ; check: v20, v21 = iadd_ifcarry v2, v5, v11
v30 = iadd_cin v3, v6, v21 v30 = iadd_ifcin v3, v6, v21
; check: v30 = iadd_cin v3, v6, v21 ; check: v30 = iadd_ifcin v3, v6, v21
return v10, v20, v30 return v10, v20, v30
} }
function %sub_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 { function %sub_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 {
ebb1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32): ebb1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32):
v10, v11 = isub_bout v1, v4 v10, v11 = isub_ifbout v1, v4
;check: v10, v11 = isub_bout v1, v4 ;check: v10, v11 = isub_ifbout v1, v4
v20, v21 = isub_borrow v2, v5, v11 v20, v21 = isub_ifborrow v2, v5, v11
; check: v20, v21 = isub_borrow v2, v5, v11 ; check: v20, v21 = isub_ifborrow v2, v5, v11
v30 = isub_bin v3, v6, v21 v30 = isub_ifbin v3, v6, v21
; check: v30 = isub_bin v3, v6, v21 ; check: v30 = isub_ifbin v3, v6, v21
return v10, v20, v30 return v10, v20, v30
} }