x64: port atomic_cas to ISLE (#4223)
This commit is contained in:
@@ -1058,6 +1058,11 @@
|
||||
(decl encode_fcmp_imm (FcmpImm) u8)
|
||||
(extern constructor encode_fcmp_imm encode_fcmp_imm)
|
||||
|
||||
;;;; Registers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(decl rax () WritableGpr)
|
||||
(extern constructor rax rax)
|
||||
|
||||
;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(type Gpr (primitive Gpr))
|
||||
@@ -2876,6 +2881,11 @@
|
||||
(rule (x64_mfence)
|
||||
(SideEffectNoResult.Inst (MInst.Fence (FenceKind.MFence))))
|
||||
|
||||
(decl x64_cmpxchg (Type Gpr Gpr SyntheticAmode) Gpr)
|
||||
(rule (x64_cmpxchg ty expected replacement addr)
|
||||
(let ((_ Unit (emit (MInst.LockCmpxchg ty replacement expected addr (rax)))))
|
||||
(rax)))
|
||||
|
||||
;;;; Automatic conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(convert Gpr InstOutput output_gpr)
|
||||
|
||||
@@ -2812,3 +2812,9 @@
|
||||
(side_effect (side_effect_concat
|
||||
(x64_movrm ty (to_amode flags address (zero_offset)) value)
|
||||
(x64_mfence))))
|
||||
|
||||
;; Rules for `atomic_cas` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (has_type (and (fits_in_64 ty) (ty_int _))
|
||||
(atomic_cas flags address expected replacement)))
|
||||
(x64_cmpxchg ty expected replacement (to_amode flags address (zero_offset))))
|
||||
|
||||
@@ -2205,32 +2205,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
}
|
||||
|
||||
Opcode::AtomicCas => {
|
||||
// This is very similar to, but not identical to, the `AtomicRmw` case. As with
|
||||
// `AtomicRmw`, there's no need to zero-extend narrow values here.
|
||||
let dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
||||
let addr = lower_to_amode(ctx, inputs[0], 0);
|
||||
let expected = put_input_in_reg(ctx, inputs[1]);
|
||||
let replacement = put_input_in_reg(ctx, inputs[2]);
|
||||
let ty_access = ty.unwrap();
|
||||
assert!(is_valid_atomic_transaction_ty(ty_access));
|
||||
|
||||
// Move the expected value into %rax. Because there's only one fixed register on
|
||||
// the input side, we don't have to use `ensure_in_vreg`, as is necessary in the
|
||||
// `AtomicRmw` case.
|
||||
ctx.emit(Inst::gen_move(
|
||||
Writable::from_reg(regs::rax()),
|
||||
expected,
|
||||
types::I64,
|
||||
));
|
||||
ctx.emit(Inst::LockCmpxchg {
|
||||
ty: ty_access,
|
||||
mem: addr.into(),
|
||||
replacement,
|
||||
expected: regs::rax(),
|
||||
dst_old: Writable::from_reg(regs::rax()),
|
||||
});
|
||||
// And finally, copy the old value at the location to its destination reg.
|
||||
ctx.emit(Inst::gen_move(dst, regs::rax(), types::I64));
|
||||
implemented_in_isle(ctx);
|
||||
}
|
||||
|
||||
Opcode::AtomicLoad => {
|
||||
|
||||
@@ -547,6 +547,12 @@ where
|
||||
fn zero_offset(&mut self) -> Offset32 {
|
||||
Offset32::new(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rax(&mut self) -> WritableGpr {
|
||||
let gpr = Gpr::new(regs::rax()).unwrap();
|
||||
WritableGpr::from_reg(gpr)
|
||||
}
|
||||
}
|
||||
|
||||
// Since x64 doesn't have 8x16 shifts and we must use a 16x8 shift instead, we
|
||||
|
||||
Reference in New Issue
Block a user