[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:
committed by
Benjamin Bouvier
parent
cadd0ac655
commit
3418fb6e18
@@ -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];
|
||||||
|
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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]));
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user