Merge pull request #2653 from bjorn3/more_atomic_ops

More atomic ops
This commit is contained in:
Chris Fallin
2021-02-18 08:34:58 -08:00
committed by GitHub
6 changed files with 104 additions and 15 deletions

View File

@@ -164,9 +164,14 @@ impl Immediates {
atomic_rmw_op_values.insert("add", "Add"); atomic_rmw_op_values.insert("add", "Add");
atomic_rmw_op_values.insert("sub", "Sub"); atomic_rmw_op_values.insert("sub", "Sub");
atomic_rmw_op_values.insert("and", "And"); atomic_rmw_op_values.insert("and", "And");
atomic_rmw_op_values.insert("nand", "Nand");
atomic_rmw_op_values.insert("or", "Or"); atomic_rmw_op_values.insert("or", "Or");
atomic_rmw_op_values.insert("xor", "Xor"); atomic_rmw_op_values.insert("xor", "Xor");
atomic_rmw_op_values.insert("xchg", "Xchg"); atomic_rmw_op_values.insert("xchg", "Xchg");
atomic_rmw_op_values.insert("umin", "Umin");
atomic_rmw_op_values.insert("umax", "Umax");
atomic_rmw_op_values.insert("smin", "Smin");
atomic_rmw_op_values.insert("smax", "Smax");
new_enum("op", "ir::AtomicRmwOp", atomic_rmw_op_values) new_enum("op", "ir::AtomicRmwOp", atomic_rmw_op_values)
.with_doc("Atomic Read-Modify-Write Ops") .with_doc("Atomic Read-Modify-Write Ops")
}, },

View File

@@ -14,12 +14,22 @@ pub enum AtomicRmwOp {
Sub, Sub,
/// And /// And
And, And,
/// Nand
Nand,
/// Or /// Or
Or, Or,
/// Xor /// Xor
Xor, Xor,
/// Exchange /// Exchange
Xchg, Xchg,
/// Unsigned min
Umin,
/// Unsigned max
Umax,
/// Signed min
Smin,
/// Signed max
Smax,
} }
impl Display for AtomicRmwOp { impl Display for AtomicRmwOp {
@@ -28,9 +38,14 @@ impl Display for AtomicRmwOp {
AtomicRmwOp::Add => "add", AtomicRmwOp::Add => "add",
AtomicRmwOp::Sub => "sub", AtomicRmwOp::Sub => "sub",
AtomicRmwOp::And => "and", AtomicRmwOp::And => "and",
AtomicRmwOp::Nand => "nand",
AtomicRmwOp::Or => "or", AtomicRmwOp::Or => "or",
AtomicRmwOp::Xor => "xor", AtomicRmwOp::Xor => "xor",
AtomicRmwOp::Xchg => "xchg", AtomicRmwOp::Xchg => "xchg",
AtomicRmwOp::Umin => "umin",
AtomicRmwOp::Umax => "umax",
AtomicRmwOp::Smin => "smin",
AtomicRmwOp::Smax => "smax",
}; };
f.write_str(s) f.write_str(s)
} }
@@ -43,9 +58,14 @@ impl FromStr for AtomicRmwOp {
"add" => Ok(AtomicRmwOp::Add), "add" => Ok(AtomicRmwOp::Add),
"sub" => Ok(AtomicRmwOp::Sub), "sub" => Ok(AtomicRmwOp::Sub),
"and" => Ok(AtomicRmwOp::And), "and" => Ok(AtomicRmwOp::And),
"nand" => Ok(AtomicRmwOp::Nand),
"or" => Ok(AtomicRmwOp::Or), "or" => Ok(AtomicRmwOp::Or),
"xor" => Ok(AtomicRmwOp::Xor), "xor" => Ok(AtomicRmwOp::Xor),
"xchg" => Ok(AtomicRmwOp::Xchg), "xchg" => Ok(AtomicRmwOp::Xchg),
"umin" => Ok(AtomicRmwOp::Umin),
"umax" => Ok(AtomicRmwOp::Umax),
"smin" => Ok(AtomicRmwOp::Smin),
"smax" => Ok(AtomicRmwOp::Smax),
_ => Err(()), _ => Err(()),
} }
} }

View File

@@ -1137,6 +1137,11 @@ impl MachInstEmit for Inst {
inst_common::AtomicRmwOp::And => 0b100_01010_00_0, inst_common::AtomicRmwOp::And => 0b100_01010_00_0,
inst_common::AtomicRmwOp::Or => 0b101_01010_00_0, inst_common::AtomicRmwOp::Or => 0b101_01010_00_0,
inst_common::AtomicRmwOp::Xor => 0b110_01010_00_0, inst_common::AtomicRmwOp::Xor => 0b110_01010_00_0,
inst_common::AtomicRmwOp::Nand
| inst_common::AtomicRmwOp::Umin
| inst_common::AtomicRmwOp::Umax
| inst_common::AtomicRmwOp::Smin
| inst_common::AtomicRmwOp::Smax => todo!("{:?}", op),
inst_common::AtomicRmwOp::Xchg => unreachable!(), inst_common::AtomicRmwOp::Xchg => unreachable!(),
}; };
sink.put4(enc_arith_rrr(bits_31_21, 0b000000, x28wr, x27, x26)); sink.put4(enc_arith_rrr(bits_31_21, 0b000000, x28wr, x27, x26));

View File

@@ -2817,22 +2817,61 @@ pub(crate) fn emit(
let i2 = Inst::mov_r_r(OperandSize::Size64, rax, r11_w); let i2 = Inst::mov_r_r(OperandSize::Size64, rax, r11_w);
i2.emit(sink, info, state); i2.emit(sink, info, state);
// opq %r10, %r11
let r10_rmi = RegMemImm::reg(r10); let r10_rmi = RegMemImm::reg(r10);
let i3 = if *op == inst_common::AtomicRmwOp::Xchg { match op {
Inst::mov_r_r(OperandSize::Size64, r10, r11_w) inst_common::AtomicRmwOp::Xchg => {
} else { // movq %r10, %r11
let alu_op = match op { let i3 = Inst::mov_r_r(OperandSize::Size64, r10, r11_w);
inst_common::AtomicRmwOp::Add => AluRmiROpcode::Add, i3.emit(sink, info, state);
inst_common::AtomicRmwOp::Sub => AluRmiROpcode::Sub, }
inst_common::AtomicRmwOp::And => AluRmiROpcode::And, inst_common::AtomicRmwOp::Nand => {
inst_common::AtomicRmwOp::Or => AluRmiROpcode::Or, // andq %r10, %r11
inst_common::AtomicRmwOp::Xor => AluRmiROpcode::Xor, let i3 =
inst_common::AtomicRmwOp::Xchg => unreachable!(), Inst::alu_rmi_r(OperandSize::Size64, AluRmiROpcode::And, r10_rmi, r11_w);
}; i3.emit(sink, info, state);
Inst::alu_rmi_r(OperandSize::Size64, alu_op, r10_rmi, r11_w)
}; // notq %r11
i3.emit(sink, info, state); let i4 = Inst::not(OperandSize::Size64, r11_w);
i4.emit(sink, info, state);
}
inst_common::AtomicRmwOp::Umin
| inst_common::AtomicRmwOp::Umax
| inst_common::AtomicRmwOp::Smin
| inst_common::AtomicRmwOp::Smax => {
// cmp %r11, %r10
let i3 = Inst::cmp_rmi_r(OperandSize::from_ty(*ty), RegMemImm::reg(r11), r10);
i3.emit(sink, info, state);
// cmovcc %r10, %r11
let cc = match op {
inst_common::AtomicRmwOp::Umin => CC::BE,
inst_common::AtomicRmwOp::Umax => CC::NB,
inst_common::AtomicRmwOp::Smin => CC::LE,
inst_common::AtomicRmwOp::Smax => CC::NL,
_ => unreachable!(),
};
let i4 = Inst::cmove(OperandSize::Size64, cc, RegMem::reg(r10), r11_w);
i4.emit(sink, info, state);
}
_ => {
// opq %r10, %r11
let alu_op = match op {
inst_common::AtomicRmwOp::Add => AluRmiROpcode::Add,
inst_common::AtomicRmwOp::Sub => AluRmiROpcode::Sub,
inst_common::AtomicRmwOp::And => AluRmiROpcode::And,
inst_common::AtomicRmwOp::Or => AluRmiROpcode::Or,
inst_common::AtomicRmwOp::Xor => AluRmiROpcode::Xor,
inst_common::AtomicRmwOp::Xchg
| inst_common::AtomicRmwOp::Nand
| inst_common::AtomicRmwOp::Umin
| inst_common::AtomicRmwOp::Umax
| inst_common::AtomicRmwOp::Smin
| inst_common::AtomicRmwOp::Smax => unreachable!(),
};
let i3 = Inst::alu_rmi_r(OperandSize::Size64, alu_op, r10_rmi, r11_w);
i3.emit(sink, info, state);
}
}
// lock cmpxchg{b,w,l,q} %r11, (%r9) // lock cmpxchg{b,w,l,q} %r11, (%r9)
// No need to call `add_trap` here, since the `i4` emit will do that. // No need to call `add_trap` here, since the `i4` emit will do that.

View File

@@ -4185,6 +4185,11 @@ fn test_x64_emit() {
"418B014989C34D89D3F0450FB1190F85EFFFFFFF", "418B014989C34D89D3F0450FB1190F85EFFFFFFF",
"atomically { 32_bits_at_[%r9]) Xchg= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }" "atomically { 32_bits_at_[%r9]) Xchg= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }"
)); ));
insns.push((
Inst::AtomicRmwSeq { ty: types::I32, op: inst_common::AtomicRmwOp::Umin, },
"418B014989C34539DA4D0F46DAF0450FB1190F85EBFFFFFF",
"atomically { 32_bits_at_[%r9]) Umin= %r10; %rax = old_value_at_[%r9]; %r11, %rflags = trash }"
));
insns.push(( insns.push((
Inst::AtomicRmwSeq { ty: types::I64, op: inst_common::AtomicRmwOp::Add, }, Inst::AtomicRmwSeq { ty: types::I64, op: inst_common::AtomicRmwOp::Add, },
"498B014989C34D01D3F04D0FB1190F85EFFFFFFF", "498B014989C34D01D3F04D0FB1190F85EFFFFFFF",

View File

@@ -56,12 +56,22 @@ pub enum AtomicRmwOp {
Sub, Sub,
/// And /// And
And, And,
/// Nand
Nand,
/// Or /// Or
Or, Or,
/// Exclusive Or /// Exclusive Or
Xor, Xor,
/// Exchange (swap operands) /// Exchange (swap operands)
Xchg, Xchg,
/// Unsigned min
Umin,
/// Unsigned max
Umax,
/// Signed min
Smin,
/// Signed max
Smax,
} }
impl AtomicRmwOp { impl AtomicRmwOp {
@@ -71,9 +81,14 @@ impl AtomicRmwOp {
ir::AtomicRmwOp::Add => AtomicRmwOp::Add, ir::AtomicRmwOp::Add => AtomicRmwOp::Add,
ir::AtomicRmwOp::Sub => AtomicRmwOp::Sub, ir::AtomicRmwOp::Sub => AtomicRmwOp::Sub,
ir::AtomicRmwOp::And => AtomicRmwOp::And, ir::AtomicRmwOp::And => AtomicRmwOp::And,
ir::AtomicRmwOp::Nand => AtomicRmwOp::Nand,
ir::AtomicRmwOp::Or => AtomicRmwOp::Or, ir::AtomicRmwOp::Or => AtomicRmwOp::Or,
ir::AtomicRmwOp::Xor => AtomicRmwOp::Xor, ir::AtomicRmwOp::Xor => AtomicRmwOp::Xor,
ir::AtomicRmwOp::Xchg => AtomicRmwOp::Xchg, ir::AtomicRmwOp::Xchg => AtomicRmwOp::Xchg,
ir::AtomicRmwOp::Umin => AtomicRmwOp::Umin,
ir::AtomicRmwOp::Umax => AtomicRmwOp::Umax,
ir::AtomicRmwOp::Smin => AtomicRmwOp::Smin,
ir::AtomicRmwOp::Smax => AtomicRmwOp::Smax,
} }
} }
} }