[AArch64] Port atomic rmw to ISLE (#4021)
Also fix and extend the current implementation: - AtomicRMWOp::Clr != AtomicRmwOp::And, as the input needs to be inverted first. - Inputs to the cmp for the RMWLoop case are sign-extended when needed. - Lower Xchg to Swp. - Lower Sub to Add with a negated input. - Added more runtests. Copyright (c) 2022, Arm Limited.
This commit is contained in:
@@ -209,10 +209,8 @@
|
|||||||
;; effect of atomically modifying a memory location in a particular way. Because we have
|
;; effect of atomically modifying a memory location in a particular way. Because we have
|
||||||
;; no way to explain to the regalloc about earlyclobber registers, this instruction has
|
;; no way to explain to the regalloc about earlyclobber registers, this instruction has
|
||||||
;; completely fixed operand registers, and we rely on the RA's coalescing to remove copies
|
;; completely fixed operand registers, and we rely on the RA's coalescing to remove copies
|
||||||
;; in the surrounding code to the extent it can. The sequence is both preceded and
|
;; in the surrounding code to the extent it can. Load- and store-exclusive instructions,
|
||||||
;; followed by a fence which is at least as comprehensive as that of the `Fence`
|
;; with acquire-release semantics, are used to access memory. The operand conventions are:
|
||||||
;; instruction below. This instruction is sequentially consistent. The operand
|
|
||||||
;; conventions are:
|
|
||||||
;;
|
;;
|
||||||
;; x25 (rd) address
|
;; x25 (rd) address
|
||||||
;; x26 (rd) second operand for `op`
|
;; x26 (rd) second operand for `op`
|
||||||
@@ -221,7 +219,20 @@
|
|||||||
;; x28 (wr) scratch reg; value afterwards has no meaning
|
;; x28 (wr) scratch reg; value afterwards has no meaning
|
||||||
(AtomicRMWLoop
|
(AtomicRMWLoop
|
||||||
(ty Type) ;; I8, I16, I32 or I64
|
(ty Type) ;; I8, I16, I32 or I64
|
||||||
(op AtomicRmwOp))
|
(op AtomicRMWLoopOp))
|
||||||
|
|
||||||
|
;; Similar to AtomicRMWLoop, a compare-and-swap operation implemented using a load-linked
|
||||||
|
;; store-conditional loop, with acquire-release semantics.
|
||||||
|
;; Note that the operand conventions, although very similar to AtomicRMWLoop, are different:
|
||||||
|
;;
|
||||||
|
;; x25 (rd) address
|
||||||
|
;; x26 (rd) expected value
|
||||||
|
;; x28 (rd) replacement value
|
||||||
|
;; x27 (wr) old value
|
||||||
|
;; x24 (wr) scratch reg; value afterwards has no meaning
|
||||||
|
(AtomicCASLoop
|
||||||
|
(ty Type) ;; I8, I16, I32 or I64
|
||||||
|
)
|
||||||
|
|
||||||
;; An atomic read-modify-write operation. These instructions require the
|
;; An atomic read-modify-write operation. These instructions require the
|
||||||
;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have
|
;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have
|
||||||
@@ -240,20 +251,6 @@
|
|||||||
(rn Reg)
|
(rn Reg)
|
||||||
(ty Type))
|
(ty Type))
|
||||||
|
|
||||||
;; Similar to AtomicRMWLoop, a compare-and-swap operation implemented using a load-linked
|
|
||||||
;; store-conditional loop.
|
|
||||||
;; This instruction is sequentially consistent.
|
|
||||||
;; Note that the operand conventions, although very similar to AtomicRMWLoop, are different:
|
|
||||||
;;
|
|
||||||
;; x25 (rd) address
|
|
||||||
;; x26 (rd) expected value
|
|
||||||
;; x28 (rd) replacement value
|
|
||||||
;; x27 (wr) old value
|
|
||||||
;; x24 (wr) scratch reg; value afterwards has no meaning
|
|
||||||
(AtomicCASLoop
|
|
||||||
(ty Type) ;; I8, I16, I32 or I64
|
|
||||||
)
|
|
||||||
|
|
||||||
;; Read `access_ty` bits from address `rt`, either 8, 16, 32 or 64-bits, and put
|
;; Read `access_ty` bits from address `rt`, either 8, 16, 32 or 64-bits, and put
|
||||||
;; it in `rn`, optionally zero-extending to fill a word or double word result.
|
;; it in `rn`, optionally zero-extending to fill a word or double word result.
|
||||||
;; This instruction is sequentially consistent.
|
;; This instruction is sequentially consistent.
|
||||||
@@ -1261,8 +1258,30 @@
|
|||||||
(Smin)
|
(Smin)
|
||||||
(Umax)
|
(Umax)
|
||||||
(Umin)
|
(Umin)
|
||||||
|
(Swp)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
;; Atomic read-modify-write operations, with acquire-release semantics,
|
||||||
|
;; implemented with a loop.
|
||||||
|
(type AtomicRMWLoopOp
|
||||||
|
(enum
|
||||||
|
(Add)
|
||||||
|
(Sub)
|
||||||
|
(And)
|
||||||
|
(Nand)
|
||||||
|
(Eor)
|
||||||
|
(Orr)
|
||||||
|
(Smax)
|
||||||
|
(Smin)
|
||||||
|
(Umax)
|
||||||
|
(Umin)
|
||||||
|
(Xchg)
|
||||||
|
))
|
||||||
|
|
||||||
|
;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
(decl use_lse () Inst)
|
||||||
|
(extern extractor use_lse use_lse)
|
||||||
|
|
||||||
;; Extractor helpers for various immmediate constants ;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Extractor helpers for various immmediate constants ;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(decl move_wide_const_from_u64 (MoveWideConst) u64)
|
(decl move_wide_const_from_u64 (MoveWideConst) u64)
|
||||||
@@ -1304,6 +1323,9 @@
|
|||||||
(decl integral_ty (Type) Type)
|
(decl integral_ty (Type) Type)
|
||||||
(extern extractor integral_ty integral_ty)
|
(extern extractor integral_ty integral_ty)
|
||||||
|
|
||||||
|
(decl valid_atomic_transaction (Type) Type)
|
||||||
|
(extern extractor valid_atomic_transaction valid_atomic_transaction)
|
||||||
|
|
||||||
;; Helper to go directly from a `Value`, when it's an `iconst`, to an `Imm12`.
|
;; Helper to go directly from a `Value`, when it's an `iconst`, to an `Imm12`.
|
||||||
(decl imm12_from_value (Imm12) Value)
|
(decl imm12_from_value (Imm12) Value)
|
||||||
(extractor
|
(extractor
|
||||||
@@ -1345,6 +1367,26 @@
|
|||||||
(decl writable_zero_reg () WritableReg)
|
(decl writable_zero_reg () WritableReg)
|
||||||
(extern constructor writable_zero_reg writable_zero_reg)
|
(extern constructor writable_zero_reg writable_zero_reg)
|
||||||
|
|
||||||
|
;; Helpers for getting a particular real register
|
||||||
|
(decl xreg (u8) Reg)
|
||||||
|
(extern constructor xreg xreg)
|
||||||
|
|
||||||
|
(decl writable_xreg (u8) WritableReg)
|
||||||
|
(extern constructor writable_xreg writable_xreg)
|
||||||
|
|
||||||
|
;; Helper for emitting `MInst.Mov64` instructions.
|
||||||
|
(decl mov64_to_real (u8 Reg) Reg)
|
||||||
|
(rule (mov64_to_real num src)
|
||||||
|
(let ((dst WritableReg (writable_xreg num))
|
||||||
|
(_ Unit (emit (MInst.Mov (operand_size $I64) dst src))))
|
||||||
|
dst))
|
||||||
|
|
||||||
|
(decl mov64_from_real (u8) Reg)
|
||||||
|
(rule (mov64_from_real num)
|
||||||
|
(let ((dst WritableReg (temp_writable_reg $I64))
|
||||||
|
(_ Unit (emit (MInst.Mov (operand_size $I64) dst (xreg num)))))
|
||||||
|
dst))
|
||||||
|
|
||||||
;; Helper for emitting `MInst.MovZ` instructions.
|
;; Helper for emitting `MInst.MovZ` instructions.
|
||||||
(decl movz (MoveWideConst OperandSize) Reg)
|
(decl movz (MoveWideConst OperandSize) Reg)
|
||||||
(rule (movz imm size)
|
(rule (movz imm size)
|
||||||
@@ -2053,3 +2095,30 @@
|
|||||||
(decl cmeq0 (Reg VectorSize) Reg)
|
(decl cmeq0 (Reg VectorSize) Reg)
|
||||||
(rule (cmeq0 rn size)
|
(rule (cmeq0 rn size)
|
||||||
(vec_misc (VecMisc2.Cmeq0) rn size))
|
(vec_misc (VecMisc2.Cmeq0) rn size))
|
||||||
|
|
||||||
|
;; Helper for emitting `MInst.AtomicRMW` instructions.
|
||||||
|
(decl lse_atomic_rmw (AtomicRMWOp Value Reg Type) Reg)
|
||||||
|
(rule (lse_atomic_rmw op p r_arg2 ty)
|
||||||
|
(let (
|
||||||
|
(r_addr Reg p)
|
||||||
|
(dst WritableReg (temp_writable_reg ty))
|
||||||
|
(_ Unit (emit (MInst.AtomicRMW op r_arg2 dst r_addr ty)))
|
||||||
|
)
|
||||||
|
dst))
|
||||||
|
|
||||||
|
;; Helper for emitting `MInst.AtomicRMWLoop` instructions.
|
||||||
|
;; - Make sure that both args are in virtual regs, since in effect
|
||||||
|
;; we have to do a parallel copy to get them safely to the AtomicRMW input
|
||||||
|
;; regs, and that's not guaranteed safe if either is in a real reg.
|
||||||
|
;; - Move the args to the preordained AtomicRMW input regs
|
||||||
|
;; - And finally, copy the preordained AtomicRMW output reg to its destination.
|
||||||
|
(decl atomic_rmw_loop (AtomicRMWLoopOp Value Value Type) Reg)
|
||||||
|
(rule (atomic_rmw_loop op p arg2 ty)
|
||||||
|
(let (
|
||||||
|
(v_addr Reg (ensure_in_vreg p $I64))
|
||||||
|
(v_arg2 Reg (ensure_in_vreg arg2 $I64))
|
||||||
|
(r_addr Reg (mov64_to_real 25 v_addr))
|
||||||
|
(r_arg2 Reg (mov64_to_real 26 v_arg2))
|
||||||
|
(_ Unit (emit (MInst.AtomicRMWLoop ty op)))
|
||||||
|
)
|
||||||
|
(mov64_from_real 27)))
|
||||||
|
|||||||
@@ -583,6 +583,13 @@ impl OperandSize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bits(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
OperandSize::Size32 => 32,
|
||||||
|
OperandSize::Size64 => 64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert from an integer type into the smallest size that fits.
|
/// Convert from an integer type into the smallest size that fits.
|
||||||
pub fn from_ty(ty: Type) -> OperandSize {
|
pub fn from_ty(ty: Type) -> OperandSize {
|
||||||
debug_assert!(!ty.is_vector());
|
debug_assert!(!ty.is_vector());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crate::ir::constant::ConstantData;
|
|||||||
use crate::ir::types::*;
|
use crate::ir::types::*;
|
||||||
use crate::ir::{LibCall, MemFlags, TrapCode};
|
use crate::ir::{LibCall, MemFlags, TrapCode};
|
||||||
use crate::isa::aarch64::inst::*;
|
use crate::isa::aarch64::inst::*;
|
||||||
|
use crate::isa::aarch64::lower::is_valid_atomic_transaction_ty;
|
||||||
use crate::machinst::{ty_bits, Reg, RegClass, Writable};
|
use crate::machinst::{ty_bits, Reg, RegClass, Writable};
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
@@ -505,7 +506,7 @@ fn enc_dmb_ish() -> u32 {
|
|||||||
0xD5033BBF
|
0xD5033BBF
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enc_ldal(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable<Reg>, rn: Reg) -> u32 {
|
fn enc_acq_rel(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable<Reg>, rn: Reg) -> u32 {
|
||||||
assert!(machreg_to_gpr(rt.to_reg()) != 31);
|
assert!(machreg_to_gpr(rt.to_reg()) != 31);
|
||||||
let sz = match ty {
|
let sz = match ty {
|
||||||
I64 => 0b11,
|
I64 => 0b11,
|
||||||
@@ -514,6 +515,10 @@ fn enc_ldal(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable<Reg>, rn: Reg) -> u
|
|||||||
I8 => 0b00,
|
I8 => 0b00,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
let bit15 = match op {
|
||||||
|
AtomicRMWOp::Swp => 0b1,
|
||||||
|
_ => 0b0,
|
||||||
|
};
|
||||||
let op = match op {
|
let op = match op {
|
||||||
AtomicRMWOp::Add => 0b000,
|
AtomicRMWOp::Add => 0b000,
|
||||||
AtomicRMWOp::Clr => 0b001,
|
AtomicRMWOp::Clr => 0b001,
|
||||||
@@ -523,10 +528,12 @@ fn enc_ldal(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable<Reg>, rn: Reg) -> u
|
|||||||
AtomicRMWOp::Smin => 0b101,
|
AtomicRMWOp::Smin => 0b101,
|
||||||
AtomicRMWOp::Umax => 0b110,
|
AtomicRMWOp::Umax => 0b110,
|
||||||
AtomicRMWOp::Umin => 0b111,
|
AtomicRMWOp::Umin => 0b111,
|
||||||
|
AtomicRMWOp::Swp => 0b000,
|
||||||
};
|
};
|
||||||
0b00_111_000_111_00000_0_000_00_00000_00000
|
0b00_111_000_111_00000_0_000_00_00000_00000
|
||||||
| (sz << 30)
|
| (sz << 30)
|
||||||
| (machreg_to_gpr(rs) << 16)
|
| (machreg_to_gpr(rs) << 16)
|
||||||
|
| bit15 << 15
|
||||||
| (op << 12)
|
| (op << 12)
|
||||||
| (machreg_to_gpr(rn) << 5)
|
| (machreg_to_gpr(rn) << 5)
|
||||||
| machreg_to_gpr(rt.to_reg())
|
| machreg_to_gpr(rt.to_reg())
|
||||||
@@ -1371,15 +1378,18 @@ impl MachInstEmit for Inst {
|
|||||||
sink.put4(enc_ccmp_imm(size, rn, imm, nzcv, cond));
|
sink.put4(enc_ccmp_imm(size, rn, imm, nzcv, cond));
|
||||||
}
|
}
|
||||||
&Inst::AtomicRMW { ty, op, rs, rt, rn } => {
|
&Inst::AtomicRMW { ty, op, rs, rt, rn } => {
|
||||||
|
assert!(is_valid_atomic_transaction_ty(ty));
|
||||||
let rs = allocs.next(rs);
|
let rs = allocs.next(rs);
|
||||||
let rt = allocs.next_writable(rt);
|
let rt = allocs.next_writable(rt);
|
||||||
let rn = allocs.next(rn);
|
let rn = allocs.next(rn);
|
||||||
sink.put4(enc_ldal(ty, op, rs, rt, rn));
|
sink.put4(enc_acq_rel(ty, op, rs, rt, rn));
|
||||||
}
|
}
|
||||||
&Inst::AtomicRMWLoop { ty, op } => {
|
&Inst::AtomicRMWLoop { ty, op } => {
|
||||||
|
assert!(is_valid_atomic_transaction_ty(ty));
|
||||||
/* Emit this:
|
/* Emit this:
|
||||||
again:
|
again:
|
||||||
ldaxr{,b,h} x/w27, [x25]
|
ldaxr{,b,h} x/w27, [x25]
|
||||||
|
// maybe sign extend
|
||||||
op x28, x27, x26 // op is add,sub,and,orr,eor
|
op x28, x27, x26 // op is add,sub,and,orr,eor
|
||||||
stlxr{,b,h} w24, x/w28, [x25]
|
stlxr{,b,h} w24, x/w28, [x25]
|
||||||
cbnz x24, again
|
cbnz x24, again
|
||||||
@@ -1414,10 +1424,31 @@ impl MachInstEmit for Inst {
|
|||||||
}
|
}
|
||||||
sink.put4(enc_ldaxr(ty, x27wr, x25)); // ldaxr x27, [x25]
|
sink.put4(enc_ldaxr(ty, x27wr, x25)); // ldaxr x27, [x25]
|
||||||
let size = OperandSize::from_ty(ty);
|
let size = OperandSize::from_ty(ty);
|
||||||
|
let sign_ext = match op {
|
||||||
|
AtomicRMWLoopOp::Smin | AtomicRMWLoopOp::Smax => match ty {
|
||||||
|
I16 => Some((ExtendOp::SXTH, 16)),
|
||||||
|
I8 => Some((ExtendOp::SXTB, 8)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// sxt{b|h} the loaded result if necessary.
|
||||||
|
if sign_ext.is_some() {
|
||||||
|
let (_, from_bits) = sign_ext.unwrap();
|
||||||
|
Inst::Extend {
|
||||||
|
rd: x27wr,
|
||||||
|
rn: x27,
|
||||||
|
signed: true,
|
||||||
|
from_bits,
|
||||||
|
to_bits: size.bits(),
|
||||||
|
}
|
||||||
|
.emit(&[], sink, emit_info, state);
|
||||||
|
}
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
AtomicRmwOp::Xchg => {} // do nothing
|
AtomicRMWLoopOp::Xchg => {} // do nothing
|
||||||
AtomicRmwOp::Nand => {
|
AtomicRMWLoopOp::Nand => {
|
||||||
// and x28, x27, x26
|
// and x28, x27, x26
|
||||||
// mvn x28, x28
|
// mvn x28, x28
|
||||||
|
|
||||||
@@ -1439,21 +1470,33 @@ impl MachInstEmit for Inst {
|
|||||||
}
|
}
|
||||||
.emit(&[], sink, emit_info, state);
|
.emit(&[], sink, emit_info, state);
|
||||||
}
|
}
|
||||||
AtomicRmwOp::Umin
|
AtomicRMWLoopOp::Umin
|
||||||
| AtomicRmwOp::Umax
|
| AtomicRMWLoopOp::Umax
|
||||||
| AtomicRmwOp::Smin
|
| AtomicRMWLoopOp::Smin
|
||||||
| AtomicRmwOp::Smax => {
|
| AtomicRMWLoopOp::Smax => {
|
||||||
// cmp x27, x26
|
// cmp x27, x26 {?sxt}
|
||||||
// csel.op x28, x27, x26
|
// csel.op x28, x27, x26
|
||||||
|
|
||||||
let cond = match op {
|
let cond = match op {
|
||||||
AtomicRmwOp::Umin => Cond::Lo,
|
AtomicRMWLoopOp::Umin => Cond::Lo,
|
||||||
AtomicRmwOp::Umax => Cond::Hi,
|
AtomicRMWLoopOp::Umax => Cond::Hi,
|
||||||
AtomicRmwOp::Smin => Cond::Lt,
|
AtomicRMWLoopOp::Smin => Cond::Lt,
|
||||||
AtomicRmwOp::Smax => Cond::Gt,
|
AtomicRMWLoopOp::Smax => Cond::Gt,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if sign_ext.is_some() {
|
||||||
|
let (extendop, _) = sign_ext.unwrap();
|
||||||
|
Inst::AluRRRExtend {
|
||||||
|
alu_op: ALUOp::SubS,
|
||||||
|
size,
|
||||||
|
rd: writable_zero_reg(),
|
||||||
|
rn: x27,
|
||||||
|
rm: x26,
|
||||||
|
extendop,
|
||||||
|
}
|
||||||
|
.emit(&[], sink, emit_info, state);
|
||||||
|
} else {
|
||||||
Inst::AluRRR {
|
Inst::AluRRR {
|
||||||
alu_op: ALUOp::SubS,
|
alu_op: ALUOp::SubS,
|
||||||
size,
|
size,
|
||||||
@@ -1462,6 +1505,7 @@ impl MachInstEmit for Inst {
|
|||||||
rm: x26,
|
rm: x26,
|
||||||
}
|
}
|
||||||
.emit(&[], sink, emit_info, state);
|
.emit(&[], sink, emit_info, state);
|
||||||
|
}
|
||||||
|
|
||||||
Inst::CSel {
|
Inst::CSel {
|
||||||
cond,
|
cond,
|
||||||
@@ -1474,17 +1518,17 @@ impl MachInstEmit for Inst {
|
|||||||
_ => {
|
_ => {
|
||||||
// add/sub/and/orr/eor x28, x27, x26
|
// add/sub/and/orr/eor x28, x27, x26
|
||||||
let alu_op = match op {
|
let alu_op = match op {
|
||||||
AtomicRmwOp::Add => ALUOp::Add,
|
AtomicRMWLoopOp::Add => ALUOp::Add,
|
||||||
AtomicRmwOp::Sub => ALUOp::Sub,
|
AtomicRMWLoopOp::Sub => ALUOp::Sub,
|
||||||
AtomicRmwOp::And => ALUOp::And,
|
AtomicRMWLoopOp::And => ALUOp::And,
|
||||||
AtomicRmwOp::Or => ALUOp::Orr,
|
AtomicRMWLoopOp::Orr => ALUOp::Orr,
|
||||||
AtomicRmwOp::Xor => ALUOp::Eor,
|
AtomicRMWLoopOp::Eor => ALUOp::Eor,
|
||||||
AtomicRmwOp::Nand
|
AtomicRMWLoopOp::Nand
|
||||||
| AtomicRmwOp::Umin
|
| AtomicRMWLoopOp::Umin
|
||||||
| AtomicRmwOp::Umax
|
| AtomicRMWLoopOp::Umax
|
||||||
| AtomicRmwOp::Smin
|
| AtomicRMWLoopOp::Smin
|
||||||
| AtomicRmwOp::Smax
|
| AtomicRMWLoopOp::Smax
|
||||||
| AtomicRmwOp::Xchg => unreachable!(),
|
| AtomicRMWLoopOp::Xchg => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Inst::AluRRR {
|
Inst::AluRRR {
|
||||||
@@ -1502,7 +1546,7 @@ impl MachInstEmit for Inst {
|
|||||||
if srcloc != SourceLoc::default() {
|
if srcloc != SourceLoc::default() {
|
||||||
sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
|
sink.add_trap(srcloc, TrapCode::HeapOutOfBounds);
|
||||||
}
|
}
|
||||||
if op == AtomicRmwOp::Xchg {
|
if op == AtomicRMWLoopOp::Xchg {
|
||||||
sink.put4(enc_stlxr(ty, x24wr, x26, x25)); // stlxr w24, x26, [x25]
|
sink.put4(enc_stlxr(ty, x24wr, x26, x25)); // stlxr w24, x26, [x25]
|
||||||
} else {
|
} else {
|
||||||
sink.put4(enc_stlxr(ty, x24wr, x28, x25)); // stlxr w24, x28, [x25]
|
sink.put4(enc_stlxr(ty, x24wr, x28, x25)); // stlxr w24, x28, [x25]
|
||||||
|
|||||||
@@ -6205,10 +6205,18 @@ fn test_aarch64_binemit() {
|
|||||||
"frintn d23, d24",
|
"frintn d23, d24",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
insns.push((
|
||||||
|
Inst::AtomicRMWLoop {
|
||||||
|
ty: I8,
|
||||||
|
op: AtomicRMWLoopOp::Sub,
|
||||||
|
},
|
||||||
|
"3BFF5F087C031A4B3CFF1808B8FFFFB5",
|
||||||
|
"1: ldaxrb w27, [x25]; sub w28, w27, w26; stlxrb w24, w28, [x25]; cbnz w24, 1b",
|
||||||
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I16,
|
ty: I16,
|
||||||
op: inst_common::AtomicRmwOp::Xor,
|
op: AtomicRMWLoopOp::Eor,
|
||||||
},
|
},
|
||||||
"3BFF5F487C031A4A3CFF1848B8FFFFB5",
|
"3BFF5F487C031A4A3CFF1848B8FFFFB5",
|
||||||
"1: ldaxrh w27, [x25]; eor w28, w27, w26; stlxrh w24, w28, [x25]; cbnz w24, 1b",
|
"1: ldaxrh w27, [x25]; eor w28, w27, w26; stlxrh w24, w28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6216,7 +6224,7 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I8,
|
ty: I8,
|
||||||
op: inst_common::AtomicRmwOp::Add,
|
op: AtomicRMWLoopOp::Add,
|
||||||
},
|
},
|
||||||
"3BFF5F087C031A0B3CFF1808B8FFFFB5",
|
"3BFF5F087C031A0B3CFF1808B8FFFFB5",
|
||||||
"1: ldaxrb w27, [x25]; add w28, w27, w26; stlxrb w24, w28, [x25]; cbnz w24, 1b",
|
"1: ldaxrb w27, [x25]; add w28, w27, w26; stlxrb w24, w28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6224,7 +6232,7 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I32,
|
ty: I32,
|
||||||
op: inst_common::AtomicRmwOp::Or,
|
op: AtomicRMWLoopOp::Orr,
|
||||||
},
|
},
|
||||||
"3BFF5F887C031A2A3CFF1888B8FFFFB5",
|
"3BFF5F887C031A2A3CFF1888B8FFFFB5",
|
||||||
"1: ldaxr w27, [x25]; orr w28, w27, w26; stlxr w24, w28, [x25]; cbnz w24, 1b",
|
"1: ldaxr w27, [x25]; orr w28, w27, w26; stlxr w24, w28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6232,7 +6240,7 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I64,
|
ty: I64,
|
||||||
op: inst_common::AtomicRmwOp::And,
|
op: AtomicRMWLoopOp::And,
|
||||||
},
|
},
|
||||||
"3BFF5FC87C031A8A3CFF18C8B8FFFFB5",
|
"3BFF5FC87C031A8A3CFF18C8B8FFFFB5",
|
||||||
"1: ldaxr x27, [x25]; and x28, x27, x26; stlxr w24, x28, [x25]; cbnz w24, 1b",
|
"1: ldaxr x27, [x25]; and x28, x27, x26; stlxr w24, x28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6240,7 +6248,7 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I8,
|
ty: I8,
|
||||||
op: inst_common::AtomicRmwOp::Xchg,
|
op: AtomicRMWLoopOp::Xchg,
|
||||||
},
|
},
|
||||||
"3BFF5F083AFF1808D8FFFFB5",
|
"3BFF5F083AFF1808D8FFFFB5",
|
||||||
"1: ldaxrb w27, [x25]; stlxrb w24, w26, [x25]; cbnz w24, 1b",
|
"1: ldaxrb w27, [x25]; stlxrb w24, w26, [x25]; cbnz w24, 1b",
|
||||||
@@ -6248,15 +6256,23 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I16,
|
ty: I16,
|
||||||
op: inst_common::AtomicRmwOp::Nand,
|
op: AtomicRMWLoopOp::Nand,
|
||||||
},
|
},
|
||||||
"3BFF5F487C031A0AFC033C2A3CFF184898FFFFB5",
|
"3BFF5F487C031A0AFC033C2A3CFF184898FFFFB5",
|
||||||
"1: ldaxrh w27, [x25]; and w28, w27, w26; mvn w28, w28; stlxrh w24, w28, [x25]; cbnz w24, 1b",
|
"1: ldaxrh w27, [x25]; and w28, w27, w26; mvn w28, w28; stlxrh w24, w28, [x25]; cbnz w24, 1b",
|
||||||
));
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AtomicRMWLoop {
|
||||||
|
ty: I16,
|
||||||
|
op: AtomicRMWLoopOp::Smin,
|
||||||
|
},
|
||||||
|
"3BFF5F487B3F00137FA33A6B7CB39A9A3CFF184878FFFFB5",
|
||||||
|
"1: ldaxrh w27, [x25]; sxth w27, w27; cmp w27, w26, sxth; csel w28, w27, w26, lt; stlxrh w24, w28, [x25]; cbnz w24, 1b",
|
||||||
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I32,
|
ty: I32,
|
||||||
op: inst_common::AtomicRmwOp::Smin,
|
op: AtomicRMWLoopOp::Smin,
|
||||||
},
|
},
|
||||||
"3BFF5F887F031A6B7CB39A9A3CFF188898FFFFB5",
|
"3BFF5F887F031A6B7CB39A9A3CFF188898FFFFB5",
|
||||||
"1: ldaxr w27, [x25]; cmp w27, w26; csel w28, w27, w26, lt; stlxr w24, w28, [x25]; cbnz w24, 1b",
|
"1: ldaxr w27, [x25]; cmp w27, w26; csel w28, w27, w26, lt; stlxr w24, w28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6264,7 +6280,7 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I64,
|
ty: I64,
|
||||||
op: inst_common::AtomicRmwOp::Smax,
|
op: AtomicRMWLoopOp::Smax,
|
||||||
},
|
},
|
||||||
"3BFF5FC87F031AEB7CC39A9A3CFF18C898FFFFB5",
|
"3BFF5FC87F031AEB7CC39A9A3CFF18C898FFFFB5",
|
||||||
"1: ldaxr x27, [x25]; cmp x27, x26; csel x28, x27, x26, gt; stlxr w24, x28, [x25]; cbnz w24, 1b",
|
"1: ldaxr x27, [x25]; cmp x27, x26; csel x28, x27, x26, gt; stlxr w24, x28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6272,7 +6288,15 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I8,
|
ty: I8,
|
||||||
op: inst_common::AtomicRmwOp::Umin,
|
op: AtomicRMWLoopOp::Smax,
|
||||||
|
},
|
||||||
|
"3BFF5F087B1F00137F833A6B7CC39A9A3CFF180878FFFFB5",
|
||||||
|
"1: ldaxrb w27, [x25]; sxtb w27, w27; cmp w27, w26, sxtb; csel w28, w27, w26, gt; stlxrb w24, w28, [x25]; cbnz w24, 1b",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AtomicRMWLoop {
|
||||||
|
ty: I8,
|
||||||
|
op: AtomicRMWLoopOp::Umin,
|
||||||
},
|
},
|
||||||
"3BFF5F087F031A6B7C339A9A3CFF180898FFFFB5",
|
"3BFF5F087F031A6B7C339A9A3CFF180898FFFFB5",
|
||||||
"1: ldaxrb w27, [x25]; cmp w27, w26; csel w28, w27, w26, lo; stlxrb w24, w28, [x25]; cbnz w24, 1b",
|
"1: ldaxrb w27, [x25]; cmp w27, w26; csel w28, w27, w26, lo; stlxrb w24, w28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6280,7 +6304,7 @@ fn test_aarch64_binemit() {
|
|||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicRMWLoop {
|
Inst::AtomicRMWLoop {
|
||||||
ty: I16,
|
ty: I16,
|
||||||
op: inst_common::AtomicRmwOp::Umax,
|
op: AtomicRMWLoopOp::Umax,
|
||||||
},
|
},
|
||||||
"3BFF5F487F031A6B7C839A9A3CFF184898FFFFB5",
|
"3BFF5F487F031A6B7C839A9A3CFF184898FFFFB5",
|
||||||
"1: ldaxrh w27, [x25]; cmp w27, w26; csel w28, w27, w26, hi; stlxrh w24, w28, [x25]; cbnz w24, 1b",
|
"1: ldaxrh w27, [x25]; cmp w27, w26; csel w28, w27, w26, hi; stlxrh w24, w28, [x25]; cbnz w24, 1b",
|
||||||
@@ -6638,6 +6662,50 @@ fn test_aarch64_binemit() {
|
|||||||
"7A73F9F8",
|
"7A73F9F8",
|
||||||
"lduminal x25, x26, [x27]",
|
"lduminal x25, x26, [x27]",
|
||||||
));
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AtomicRMW {
|
||||||
|
ty: I8,
|
||||||
|
op: AtomicRMWOp::Swp,
|
||||||
|
rs: xreg(28),
|
||||||
|
rt: writable_xreg(29),
|
||||||
|
rn: xreg(30),
|
||||||
|
},
|
||||||
|
"DD83FC38",
|
||||||
|
"swpalb w28, fp, [lr]",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AtomicRMW {
|
||||||
|
ty: I16,
|
||||||
|
op: AtomicRMWOp::Swp,
|
||||||
|
rs: xreg(0),
|
||||||
|
rt: writable_xreg(1),
|
||||||
|
rn: xreg(2),
|
||||||
|
},
|
||||||
|
"4180E078",
|
||||||
|
"swpalh w0, w1, [x2]",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AtomicRMW {
|
||||||
|
ty: I32,
|
||||||
|
op: AtomicRMWOp::Swp,
|
||||||
|
rs: xreg(3),
|
||||||
|
rt: writable_xreg(4),
|
||||||
|
rn: xreg(5),
|
||||||
|
},
|
||||||
|
"A480E3B8",
|
||||||
|
"swpal w3, w4, [x5]",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AtomicRMW {
|
||||||
|
ty: I64,
|
||||||
|
op: AtomicRMWOp::Swp,
|
||||||
|
rs: xreg(6),
|
||||||
|
rt: writable_xreg(7),
|
||||||
|
rn: xreg(8),
|
||||||
|
},
|
||||||
|
"0781E6F8",
|
||||||
|
"swpal x6, x7, [x8]",
|
||||||
|
));
|
||||||
|
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::AtomicCAS {
|
Inst::AtomicCAS {
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ mod emit_tests;
|
|||||||
// Instructions (top level): definition
|
// Instructions (top level): definition
|
||||||
|
|
||||||
pub use crate::isa::aarch64::lower::isle::generated_code::{
|
pub use crate::isa::aarch64::lower::isle::generated_code::{
|
||||||
ALUOp, ALUOp3, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode, FpuToIntOp,
|
ALUOp, ALUOp3, AtomicRMWLoopOp, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode,
|
||||||
IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2, VecPairOp,
|
FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2,
|
||||||
VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
|
VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A floating-point unit (FPU) operation with two args, a register and an immediate.
|
/// A floating-point unit (FPU) operation with two args, a register and an immediate.
|
||||||
@@ -676,13 +676,15 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
|
|||||||
&Inst::CCmpImm { rn, .. } => {
|
&Inst::CCmpImm { rn, .. } => {
|
||||||
collector.reg_use(rn);
|
collector.reg_use(rn);
|
||||||
}
|
}
|
||||||
&Inst::AtomicRMWLoop { .. } => {
|
&Inst::AtomicRMWLoop { op, .. } => {
|
||||||
collector.reg_use(xreg(25));
|
collector.reg_use(xreg(25));
|
||||||
collector.reg_use(xreg(26));
|
collector.reg_use(xreg(26));
|
||||||
collector.reg_def(writable_xreg(24));
|
collector.reg_def(writable_xreg(24));
|
||||||
collector.reg_def(writable_xreg(27));
|
collector.reg_def(writable_xreg(27));
|
||||||
|
if op != AtomicRMWLoopOp::Xchg {
|
||||||
collector.reg_def(writable_xreg(28));
|
collector.reg_def(writable_xreg(28));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&Inst::AtomicRMW { rs, rt, rn, .. } => {
|
&Inst::AtomicRMW { rs, rt, rn, .. } => {
|
||||||
collector.reg_use(rs);
|
collector.reg_use(rs);
|
||||||
collector.reg_def(rt);
|
collector.reg_def(rt);
|
||||||
@@ -1538,6 +1540,7 @@ impl Inst {
|
|||||||
AtomicRMWOp::Umax => "ldumaxal",
|
AtomicRMWOp::Umax => "ldumaxal",
|
||||||
AtomicRMWOp::Smin => "ldsminal",
|
AtomicRMWOp::Smin => "ldsminal",
|
||||||
AtomicRMWOp::Umin => "lduminal",
|
AtomicRMWOp::Umin => "lduminal",
|
||||||
|
AtomicRMWOp::Swp => "swpal",
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = OperandSize::from_ty(ty);
|
let size = OperandSize::from_ty(ty);
|
||||||
@@ -1569,28 +1572,39 @@ impl Inst {
|
|||||||
loop_str.push_str(&format!("ldaxr{} {}, [{}]; ", ty_suffix, r_tmp, r_addr));
|
loop_str.push_str(&format!("ldaxr{} {}, [{}]; ", ty_suffix, r_tmp, r_addr));
|
||||||
|
|
||||||
let op_str = match op {
|
let op_str = match op {
|
||||||
inst_common::AtomicRmwOp::Add => "add",
|
AtomicRMWLoopOp::Add => "add",
|
||||||
inst_common::AtomicRmwOp::Sub => "sub",
|
AtomicRMWLoopOp::Sub => "sub",
|
||||||
inst_common::AtomicRmwOp::Xor => "eor",
|
AtomicRMWLoopOp::Eor => "eor",
|
||||||
inst_common::AtomicRmwOp::Or => "orr",
|
AtomicRMWLoopOp::Orr => "orr",
|
||||||
inst_common::AtomicRmwOp::And => "and",
|
AtomicRMWLoopOp::And => "and",
|
||||||
_ => "",
|
_ => "",
|
||||||
};
|
};
|
||||||
|
|
||||||
if op_str.is_empty() {
|
if op_str.is_empty() {
|
||||||
match op {
|
match op {
|
||||||
inst_common::AtomicRmwOp::Xchg => r_dst = r_arg2,
|
AtomicRMWLoopOp::Xchg => r_dst = r_arg2,
|
||||||
inst_common::AtomicRmwOp::Nand => {
|
AtomicRMWLoopOp::Nand => {
|
||||||
loop_str.push_str(&format!("and {}, {}, {}; ", r_dst, r_tmp, r_arg2));
|
loop_str.push_str(&format!("and {}, {}, {}; ", r_dst, r_tmp, r_arg2));
|
||||||
loop_str.push_str(&format!("mvn {}, {}; ", r_dst, r_dst));
|
loop_str.push_str(&format!("mvn {}, {}; ", r_dst, r_dst));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
if (op == AtomicRMWLoopOp::Smin || op == AtomicRMWLoopOp::Smax)
|
||||||
|
&& (ty == I8 || ty == I16)
|
||||||
|
{
|
||||||
|
loop_str
|
||||||
|
.push_str(&format!("sxt{} {}, {}; ", ty_suffix, r_tmp, r_tmp));
|
||||||
|
loop_str.push_str(&format!(
|
||||||
|
"cmp {}, {}, sxt{}; ",
|
||||||
|
r_tmp, r_arg2, ty_suffix
|
||||||
|
));
|
||||||
|
} else {
|
||||||
loop_str.push_str(&format!("cmp {}, {}; ", r_tmp, r_arg2));
|
loop_str.push_str(&format!("cmp {}, {}; ", r_tmp, r_arg2));
|
||||||
|
}
|
||||||
let cond = match op {
|
let cond = match op {
|
||||||
inst_common::AtomicRmwOp::Smin => "lt",
|
AtomicRMWLoopOp::Smin => "lt",
|
||||||
inst_common::AtomicRmwOp::Smax => "gt",
|
AtomicRMWLoopOp::Smax => "gt",
|
||||||
inst_common::AtomicRmwOp::Umin => "lo",
|
AtomicRMWLoopOp::Umin => "lo",
|
||||||
inst_common::AtomicRmwOp::Umax => "hi",
|
AtomicRMWLoopOp::Umax => "hi",
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
loop_str.push_str(&format!(
|
loop_str.push_str(&format!(
|
||||||
|
|||||||
@@ -1196,3 +1196,77 @@
|
|||||||
(let ((rn Reg y)
|
(let ((rn Reg y)
|
||||||
(vec_size VectorSize (vector_size ty)))
|
(vec_size VectorSize (vector_size ty)))
|
||||||
(value_reg (int_cmp_zero_swap cond rn vec_size))))
|
(value_reg (int_cmp_zero_swap cond rn vec_size))))
|
||||||
|
|
||||||
|
;;;; Rules for `AtomicRMW` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Add) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Add) addr src ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Xor) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Eor) addr src ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Or) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Set) addr src ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Smax) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Smax) addr src ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Smin) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Smin) addr src ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Umax) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Umax) addr src ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Umin) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Umin) addr src ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Sub) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Add) addr (sub ty (zero_reg) src) ty))
|
||||||
|
(rule (lower (and (use_lse)
|
||||||
|
(has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.And) addr src))))
|
||||||
|
(lse_atomic_rmw (AtomicRMWOp.Clr) addr (eon ty src (zero_reg)) ty))
|
||||||
|
|
||||||
|
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Add) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Add) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Sub) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Sub) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.And) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.And) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Nand) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Nand) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Or) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Orr) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Xor) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Eor) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Smin) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Smin) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Smax) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Smax) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Umin) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Umin) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Umax) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Umax) addr src ty))
|
||||||
|
(rule (lower (has_type (valid_atomic_transaction ty)
|
||||||
|
(atomic_rmw flags (AtomicRmwOp.Xchg) addr src)))
|
||||||
|
(atomic_rmw_loop (AtomicRMWLoopOp.Xchg) addr src ty))
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ pub mod generated_code;
|
|||||||
|
|
||||||
// Types that the generated ISLE code uses via `use super::*`.
|
// Types that the generated ISLE code uses via `use super::*`.
|
||||||
use super::{
|
use super::{
|
||||||
writable_zero_reg, zero_reg, AMode, ASIMDFPModImm, ASIMDMovModImm, AtomicRmwOp, BranchTarget,
|
writable_zero_reg, zero_reg, AMode, ASIMDFPModImm, ASIMDMovModImm, BranchTarget, CallIndInfo,
|
||||||
CallIndInfo, CallInfo, Cond, CondBrKind, ExtendOp, FPUOpRI, FloatCC, Imm12, ImmLogic, ImmShift,
|
CallInfo, Cond, CondBrKind, ExtendOp, FPUOpRI, FloatCC, Imm12, ImmLogic, ImmShift,
|
||||||
Inst as MInst, IntCC, JTSequenceInfo, MachLabel, MoveWideConst, MoveWideOp, NarrowValueMode,
|
Inst as MInst, IntCC, JTSequenceInfo, MachLabel, MoveWideConst, MoveWideOp, NarrowValueMode,
|
||||||
Opcode, OperandSize, PairAMode, Reg, ScalarSize, ShiftOpAndAmt, UImm5, VecMisc2, VectorSize,
|
Opcode, OperandSize, PairAMode, Reg, ScalarSize, ShiftOpAndAmt, UImm5, VecMisc2, VectorSize,
|
||||||
NZCV,
|
NZCV,
|
||||||
@@ -17,10 +17,11 @@ use crate::settings::Flags;
|
|||||||
use crate::{
|
use crate::{
|
||||||
binemit::CodeOffset,
|
binemit::CodeOffset,
|
||||||
ir::{
|
ir::{
|
||||||
immediates::*, types::*, ExternalName, Inst, InstructionData, MemFlags, TrapCode, Value,
|
immediates::*, types::*, AtomicRmwOp, ExternalName, Inst, InstructionData, MemFlags,
|
||||||
ValueList,
|
TrapCode, Value, ValueList,
|
||||||
},
|
},
|
||||||
isa::aarch64::inst::args::{ShiftOp, ShiftOpShiftImm},
|
isa::aarch64::inst::args::{ShiftOp, ShiftOpShiftImm},
|
||||||
|
isa::aarch64::lower::{is_valid_atomic_transaction_ty, writable_xreg, xreg},
|
||||||
isa::unwind::UnwindInst,
|
isa::unwind::UnwindInst,
|
||||||
machinst::{ty_bits, InsnOutput, LowerCtx},
|
machinst::{ty_bits, InsnOutput, LowerCtx},
|
||||||
};
|
};
|
||||||
@@ -66,6 +67,14 @@ where
|
|||||||
{
|
{
|
||||||
isle_prelude_methods!();
|
isle_prelude_methods!();
|
||||||
|
|
||||||
|
fn use_lse(&mut self, _: Inst) -> Option<()> {
|
||||||
|
if self.isa_flags.use_lse() {
|
||||||
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn move_wide_const_from_u64(&mut self, n: u64) -> Option<MoveWideConst> {
|
fn move_wide_const_from_u64(&mut self, n: u64) -> Option<MoveWideConst> {
|
||||||
MoveWideConst::maybe_from_u64(n)
|
MoveWideConst::maybe_from_u64(n)
|
||||||
}
|
}
|
||||||
@@ -114,6 +123,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn valid_atomic_transaction(&mut self, ty: Type) -> Option<Type> {
|
||||||
|
if is_valid_atomic_transaction_ty(ty) {
|
||||||
|
Some(ty)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is the fallback case for loading a 64-bit integral constant into a
|
/// This is the fallback case for loading a 64-bit integral constant into a
|
||||||
/// register.
|
/// register.
|
||||||
///
|
///
|
||||||
@@ -194,6 +211,14 @@ where
|
|||||||
zero_reg()
|
zero_reg()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn xreg(&mut self, index: u8) -> Reg {
|
||||||
|
xreg(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writable_xreg(&mut self, index: u8) -> WritableReg {
|
||||||
|
writable_xreg(index)
|
||||||
|
}
|
||||||
|
|
||||||
fn extended_value_from_value(&mut self, val: Value) -> Option<ExtendedValue> {
|
fn extended_value_from_value(&mut self, val: Value) -> Option<ExtendedValue> {
|
||||||
let (val, extend) =
|
let (val, extend) =
|
||||||
super::get_as_extended_value(self.lower_ctx, val, NarrowValueMode::None)?;
|
super::get_as_extended_value(self.lower_ctx, val, NarrowValueMode::None)?;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
src/clif.isle 443b34b797fc8ace
|
src/clif.isle 443b34b797fc8ace
|
||||||
src/prelude.isle d8a93eb727abd7f4
|
src/prelude.isle a7915a6b88310eb5
|
||||||
src/isa/aarch64/inst.isle 77984cc33a05be7
|
src/isa/aarch64/inst.isle a2c0ae729bfa24a8
|
||||||
src/isa/aarch64/lower.isle 71c7e603b0e4bdef
|
src/isa/aarch64/lower.isle 15641ca7f0ac061a
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -237,48 +237,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
ctx.emit(inst);
|
ctx.emit(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::AtomicRmw => {
|
Opcode::AtomicRmw => implemented_in_isle(ctx),
|
||||||
let r_dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
|
||||||
let mut r_addr = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
|
|
||||||
let mut r_arg2 = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
|
|
||||||
let ty_access = ty.unwrap();
|
|
||||||
assert!(is_valid_atomic_transaction_ty(ty_access));
|
|
||||||
|
|
||||||
let op = inst_common::AtomicRmwOp::from(ctx.data(insn).atomic_rmw_op().unwrap());
|
|
||||||
let lse_op = match op {
|
|
||||||
AtomicRmwOp::Add => Some(AtomicRMWOp::Add),
|
|
||||||
AtomicRmwOp::And => Some(AtomicRMWOp::Clr),
|
|
||||||
AtomicRmwOp::Xor => Some(AtomicRMWOp::Eor),
|
|
||||||
AtomicRmwOp::Or => Some(AtomicRMWOp::Set),
|
|
||||||
AtomicRmwOp::Smax => Some(AtomicRMWOp::Smax),
|
|
||||||
AtomicRmwOp::Umax => Some(AtomicRMWOp::Umax),
|
|
||||||
AtomicRmwOp::Smin => Some(AtomicRMWOp::Smin),
|
|
||||||
AtomicRmwOp::Umin => Some(AtomicRMWOp::Umin),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
if isa_flags.use_lse() && lse_op.is_some() {
|
|
||||||
ctx.emit(Inst::AtomicRMW {
|
|
||||||
op: lse_op.unwrap(),
|
|
||||||
rs: r_arg2,
|
|
||||||
rt: r_dst,
|
|
||||||
rn: r_addr,
|
|
||||||
ty: ty_access,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Make sure that both args are in virtual regs, since in effect
|
|
||||||
// we have to do a parallel copy to get them safely to the AtomicRMW input
|
|
||||||
// regs, and that's not guaranteed safe if either is in a real reg.
|
|
||||||
r_addr = ctx.ensure_in_vreg(r_addr, I64);
|
|
||||||
r_arg2 = ctx.ensure_in_vreg(r_arg2, I64);
|
|
||||||
// Move the args to the preordained AtomicRMW input regs
|
|
||||||
ctx.emit(Inst::gen_move(Writable::from_reg(xreg(25)), r_addr, I64));
|
|
||||||
ctx.emit(Inst::gen_move(Writable::from_reg(xreg(26)), r_arg2, I64));
|
|
||||||
ctx.emit(Inst::AtomicRMWLoop { ty: ty_access, op });
|
|
||||||
// And finally, copy the preordained AtomicRMW output reg to its destination.
|
|
||||||
ctx.emit(Inst::gen_move(r_dst, xreg(27), I64));
|
|
||||||
// Also, x24 and x28 are trashed. `fn aarch64_get_regs` must mention that.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Opcode::AtomicCas => {
|
Opcode::AtomicCas => {
|
||||||
let r_dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
let r_dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
src/clif.isle 443b34b797fc8ace
|
src/clif.isle 443b34b797fc8ace
|
||||||
src/prelude.isle d8a93eb727abd7f4
|
src/prelude.isle a7915a6b88310eb5
|
||||||
src/isa/s390x/inst.isle 8218bd9e8556446b
|
src/isa/s390x/inst.isle 8218bd9e8556446b
|
||||||
src/isa/s390x/lower.isle 6a8de81f8dc4e568
|
src/isa/s390x/lower.isle 6a8de81f8dc4e568
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub trait Context {
|
|||||||
fn invalid_reg(&mut self) -> Reg;
|
fn invalid_reg(&mut self) -> Reg;
|
||||||
fn put_in_reg(&mut self, arg0: Value) -> Reg;
|
fn put_in_reg(&mut self, arg0: Value) -> Reg;
|
||||||
fn put_in_regs(&mut self, arg0: Value) -> ValueRegs;
|
fn put_in_regs(&mut self, arg0: Value) -> ValueRegs;
|
||||||
|
fn ensure_in_vreg(&mut self, arg0: Reg, arg1: Type) -> Reg;
|
||||||
fn value_regs_get(&mut self, arg0: ValueRegs, arg1: usize) -> Reg;
|
fn value_regs_get(&mut self, arg0: ValueRegs, arg1: usize) -> Reg;
|
||||||
fn u8_as_u64(&mut self, arg0: u8) -> u64;
|
fn u8_as_u64(&mut self, arg0: u8) -> u64;
|
||||||
fn u16_as_u64(&mut self, arg0: u16) -> u64;
|
fn u16_as_u64(&mut self, arg0: u16) -> u64;
|
||||||
@@ -155,14 +156,14 @@ pub trait Context {
|
|||||||
fn same_reg(&mut self, arg0: Reg, arg1: WritableReg) -> Option<()>;
|
fn same_reg(&mut self, arg0: Reg, arg1: WritableReg) -> Option<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal type SideEffectNoResult: defined at src/prelude.isle line 407.
|
/// Internal type SideEffectNoResult: defined at src/prelude.isle line 412.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum SideEffectNoResult {
|
pub enum SideEffectNoResult {
|
||||||
Inst { inst: MInst },
|
Inst { inst: MInst },
|
||||||
Inst2 { inst1: MInst, inst2: MInst },
|
Inst2 { inst1: MInst, inst2: MInst },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal type ProducesFlags: defined at src/prelude.isle line 434.
|
/// Internal type ProducesFlags: defined at src/prelude.isle line 439.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ProducesFlags {
|
pub enum ProducesFlags {
|
||||||
ProducesFlagsSideEffect { inst: MInst },
|
ProducesFlagsSideEffect { inst: MInst },
|
||||||
@@ -170,7 +171,7 @@ pub enum ProducesFlags {
|
|||||||
ProducesFlagsReturnsResultWithConsumer { inst: MInst, result: Reg },
|
ProducesFlagsReturnsResultWithConsumer { inst: MInst, result: Reg },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal type ConsumesFlags: defined at src/prelude.isle line 445.
|
/// Internal type ConsumesFlags: defined at src/prelude.isle line 450.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ConsumesFlags {
|
pub enum ConsumesFlags {
|
||||||
ConsumesFlagsReturnsResultWithProducer {
|
ConsumesFlagsReturnsResultWithProducer {
|
||||||
@@ -943,7 +944,7 @@ pub fn constructor_temp_reg<C: Context>(ctx: &mut C, arg0: Type) -> Option<Reg>
|
|||||||
// Generated as internal constructor for term lo_reg.
|
// Generated as internal constructor for term lo_reg.
|
||||||
pub fn constructor_lo_reg<C: Context>(ctx: &mut C, arg0: Value) -> Option<Reg> {
|
pub fn constructor_lo_reg<C: Context>(ctx: &mut C, arg0: Value) -> Option<Reg> {
|
||||||
let pattern0_0 = arg0;
|
let pattern0_0 = arg0;
|
||||||
// Rule at src/prelude.isle line 145.
|
// Rule at src/prelude.isle line 150.
|
||||||
let expr0_0 = C::put_in_regs(ctx, pattern0_0);
|
let expr0_0 = C::put_in_regs(ctx, pattern0_0);
|
||||||
let expr1_0: usize = 0;
|
let expr1_0: usize = 0;
|
||||||
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
||||||
@@ -960,7 +961,7 @@ pub fn constructor_side_effect<C: Context>(
|
|||||||
&SideEffectNoResult::Inst {
|
&SideEffectNoResult::Inst {
|
||||||
inst: ref pattern1_0,
|
inst: ref pattern1_0,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 415.
|
// Rule at src/prelude.isle line 420.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::output_none(ctx);
|
let expr1_0 = C::output_none(ctx);
|
||||||
return Some(expr1_0);
|
return Some(expr1_0);
|
||||||
@@ -969,7 +970,7 @@ pub fn constructor_side_effect<C: Context>(
|
|||||||
inst1: ref pattern1_0,
|
inst1: ref pattern1_0,
|
||||||
inst2: ref pattern1_1,
|
inst2: ref pattern1_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 418.
|
// Rule at src/prelude.isle line 423.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern1_1);
|
let expr1_0 = C::emit(ctx, pattern1_1);
|
||||||
let expr2_0 = C::output_none(ctx);
|
let expr2_0 = C::output_none(ctx);
|
||||||
@@ -996,7 +997,7 @@ pub fn constructor_side_effect_concat<C: Context>(
|
|||||||
inst: ref pattern3_0,
|
inst: ref pattern3_0,
|
||||||
} = pattern2_0
|
} = pattern2_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 424.
|
// Rule at src/prelude.isle line 429.
|
||||||
let expr0_0 = SideEffectNoResult::Inst2 {
|
let expr0_0 = SideEffectNoResult::Inst2 {
|
||||||
inst1: pattern1_0.clone(),
|
inst1: pattern1_0.clone(),
|
||||||
inst2: pattern3_0.clone(),
|
inst2: pattern3_0.clone(),
|
||||||
@@ -1018,7 +1019,7 @@ pub fn constructor_produces_flags_get_reg<C: Context>(
|
|||||||
result: pattern1_1,
|
result: pattern1_1,
|
||||||
} = pattern0_0
|
} = pattern0_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 461.
|
// Rule at src/prelude.isle line 466.
|
||||||
return Some(pattern1_1);
|
return Some(pattern1_1);
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
@@ -1035,7 +1036,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
|
|||||||
inst: ref pattern1_0,
|
inst: ref pattern1_0,
|
||||||
result: pattern1_1,
|
result: pattern1_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 466.
|
// Rule at src/prelude.isle line 471.
|
||||||
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
||||||
inst: pattern1_0.clone(),
|
inst: pattern1_0.clone(),
|
||||||
};
|
};
|
||||||
@@ -1045,7 +1046,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
|
|||||||
inst: ref pattern1_0,
|
inst: ref pattern1_0,
|
||||||
result: pattern1_1,
|
result: pattern1_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 468.
|
// Rule at src/prelude.isle line 473.
|
||||||
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
||||||
inst: pattern1_0.clone(),
|
inst: pattern1_0.clone(),
|
||||||
};
|
};
|
||||||
@@ -1074,7 +1075,7 @@ pub fn constructor_consumes_flags_concat<C: Context>(
|
|||||||
result: pattern3_1,
|
result: pattern3_1,
|
||||||
} = pattern2_0
|
} = pattern2_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 475.
|
// Rule at src/prelude.isle line 480.
|
||||||
let expr0_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
let expr0_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
||||||
let expr1_0 = ConsumesFlags::ConsumesFlagsTwiceReturnsValueRegs {
|
let expr1_0 = ConsumesFlags::ConsumesFlagsTwiceReturnsValueRegs {
|
||||||
inst1: pattern1_0.clone(),
|
inst1: pattern1_0.clone(),
|
||||||
@@ -1104,7 +1105,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
inst: ref pattern3_0,
|
inst: ref pattern3_0,
|
||||||
result: pattern3_1,
|
result: pattern3_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 500.
|
// Rule at src/prelude.isle line 505.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::value_reg(ctx, pattern3_1);
|
let expr2_0 = C::value_reg(ctx, pattern3_1);
|
||||||
@@ -1115,7 +1116,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
inst2: ref pattern3_1,
|
inst2: ref pattern3_1,
|
||||||
result: pattern3_2,
|
result: pattern3_2,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 506.
|
// Rule at src/prelude.isle line 511.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::emit(ctx, pattern3_1);
|
let expr2_0 = C::emit(ctx, pattern3_1);
|
||||||
@@ -1128,7 +1129,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
inst4: ref pattern3_3,
|
inst4: ref pattern3_3,
|
||||||
result: pattern3_4,
|
result: pattern3_4,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 518.
|
// Rule at src/prelude.isle line 523.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::emit(ctx, pattern3_1);
|
let expr2_0 = C::emit(ctx, pattern3_1);
|
||||||
@@ -1149,7 +1150,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
result: pattern3_1,
|
result: pattern3_1,
|
||||||
} = pattern2_0
|
} = pattern2_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 494.
|
// Rule at src/prelude.isle line 499.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
let expr2_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
||||||
@@ -1169,7 +1170,7 @@ pub fn constructor_with_flags_reg<C: Context>(
|
|||||||
) -> Option<Reg> {
|
) -> Option<Reg> {
|
||||||
let pattern0_0 = arg0;
|
let pattern0_0 = arg0;
|
||||||
let pattern1_0 = arg1;
|
let pattern1_0 = arg1;
|
||||||
// Rule at src/prelude.isle line 535.
|
// Rule at src/prelude.isle line 540.
|
||||||
let expr0_0 = constructor_with_flags(ctx, pattern0_0, pattern1_0)?;
|
let expr0_0 = constructor_with_flags(ctx, pattern0_0, pattern1_0)?;
|
||||||
let expr1_0: usize = 0;
|
let expr1_0: usize = 0;
|
||||||
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
src/clif.isle 443b34b797fc8ace
|
src/clif.isle 443b34b797fc8ace
|
||||||
src/prelude.isle d8a93eb727abd7f4
|
src/prelude.isle a7915a6b88310eb5
|
||||||
src/isa/x64/inst.isle 6dcba190988a695
|
src/isa/x64/inst.isle 6dcba190988a695
|
||||||
src/isa/x64/lower.isle b95161bdf07b9365
|
src/isa/x64/lower.isle b95161bdf07b9365
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub trait Context {
|
|||||||
fn invalid_reg(&mut self) -> Reg;
|
fn invalid_reg(&mut self) -> Reg;
|
||||||
fn put_in_reg(&mut self, arg0: Value) -> Reg;
|
fn put_in_reg(&mut self, arg0: Value) -> Reg;
|
||||||
fn put_in_regs(&mut self, arg0: Value) -> ValueRegs;
|
fn put_in_regs(&mut self, arg0: Value) -> ValueRegs;
|
||||||
|
fn ensure_in_vreg(&mut self, arg0: Reg, arg1: Type) -> Reg;
|
||||||
fn value_regs_get(&mut self, arg0: ValueRegs, arg1: usize) -> Reg;
|
fn value_regs_get(&mut self, arg0: ValueRegs, arg1: usize) -> Reg;
|
||||||
fn u8_as_u64(&mut self, arg0: u8) -> u64;
|
fn u8_as_u64(&mut self, arg0: u8) -> u64;
|
||||||
fn u16_as_u64(&mut self, arg0: u16) -> u64;
|
fn u16_as_u64(&mut self, arg0: u16) -> u64;
|
||||||
@@ -163,14 +164,14 @@ pub trait Context {
|
|||||||
fn popcount_low_mask(&mut self) -> VCodeConstant;
|
fn popcount_low_mask(&mut self) -> VCodeConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal type SideEffectNoResult: defined at src/prelude.isle line 407.
|
/// Internal type SideEffectNoResult: defined at src/prelude.isle line 412.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum SideEffectNoResult {
|
pub enum SideEffectNoResult {
|
||||||
Inst { inst: MInst },
|
Inst { inst: MInst },
|
||||||
Inst2 { inst1: MInst, inst2: MInst },
|
Inst2 { inst1: MInst, inst2: MInst },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal type ProducesFlags: defined at src/prelude.isle line 434.
|
/// Internal type ProducesFlags: defined at src/prelude.isle line 439.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ProducesFlags {
|
pub enum ProducesFlags {
|
||||||
ProducesFlagsSideEffect { inst: MInst },
|
ProducesFlagsSideEffect { inst: MInst },
|
||||||
@@ -178,7 +179,7 @@ pub enum ProducesFlags {
|
|||||||
ProducesFlagsReturnsResultWithConsumer { inst: MInst, result: Reg },
|
ProducesFlagsReturnsResultWithConsumer { inst: MInst, result: Reg },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal type ConsumesFlags: defined at src/prelude.isle line 445.
|
/// Internal type ConsumesFlags: defined at src/prelude.isle line 450.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ConsumesFlags {
|
pub enum ConsumesFlags {
|
||||||
ConsumesFlagsReturnsResultWithProducer {
|
ConsumesFlagsReturnsResultWithProducer {
|
||||||
@@ -562,7 +563,7 @@ pub fn constructor_temp_reg<C: Context>(ctx: &mut C, arg0: Type) -> Option<Reg>
|
|||||||
// Generated as internal constructor for term lo_reg.
|
// Generated as internal constructor for term lo_reg.
|
||||||
pub fn constructor_lo_reg<C: Context>(ctx: &mut C, arg0: Value) -> Option<Reg> {
|
pub fn constructor_lo_reg<C: Context>(ctx: &mut C, arg0: Value) -> Option<Reg> {
|
||||||
let pattern0_0 = arg0;
|
let pattern0_0 = arg0;
|
||||||
// Rule at src/prelude.isle line 145.
|
// Rule at src/prelude.isle line 150.
|
||||||
let expr0_0 = C::put_in_regs(ctx, pattern0_0);
|
let expr0_0 = C::put_in_regs(ctx, pattern0_0);
|
||||||
let expr1_0: usize = 0;
|
let expr1_0: usize = 0;
|
||||||
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
||||||
@@ -579,7 +580,7 @@ pub fn constructor_side_effect<C: Context>(
|
|||||||
&SideEffectNoResult::Inst {
|
&SideEffectNoResult::Inst {
|
||||||
inst: ref pattern1_0,
|
inst: ref pattern1_0,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 415.
|
// Rule at src/prelude.isle line 420.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::output_none(ctx);
|
let expr1_0 = C::output_none(ctx);
|
||||||
return Some(expr1_0);
|
return Some(expr1_0);
|
||||||
@@ -588,7 +589,7 @@ pub fn constructor_side_effect<C: Context>(
|
|||||||
inst1: ref pattern1_0,
|
inst1: ref pattern1_0,
|
||||||
inst2: ref pattern1_1,
|
inst2: ref pattern1_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 418.
|
// Rule at src/prelude.isle line 423.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern1_1);
|
let expr1_0 = C::emit(ctx, pattern1_1);
|
||||||
let expr2_0 = C::output_none(ctx);
|
let expr2_0 = C::output_none(ctx);
|
||||||
@@ -615,7 +616,7 @@ pub fn constructor_side_effect_concat<C: Context>(
|
|||||||
inst: ref pattern3_0,
|
inst: ref pattern3_0,
|
||||||
} = pattern2_0
|
} = pattern2_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 424.
|
// Rule at src/prelude.isle line 429.
|
||||||
let expr0_0 = SideEffectNoResult::Inst2 {
|
let expr0_0 = SideEffectNoResult::Inst2 {
|
||||||
inst1: pattern1_0.clone(),
|
inst1: pattern1_0.clone(),
|
||||||
inst2: pattern3_0.clone(),
|
inst2: pattern3_0.clone(),
|
||||||
@@ -637,7 +638,7 @@ pub fn constructor_produces_flags_get_reg<C: Context>(
|
|||||||
result: pattern1_1,
|
result: pattern1_1,
|
||||||
} = pattern0_0
|
} = pattern0_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 461.
|
// Rule at src/prelude.isle line 466.
|
||||||
return Some(pattern1_1);
|
return Some(pattern1_1);
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
@@ -654,7 +655,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
|
|||||||
inst: ref pattern1_0,
|
inst: ref pattern1_0,
|
||||||
result: pattern1_1,
|
result: pattern1_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 466.
|
// Rule at src/prelude.isle line 471.
|
||||||
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
||||||
inst: pattern1_0.clone(),
|
inst: pattern1_0.clone(),
|
||||||
};
|
};
|
||||||
@@ -664,7 +665,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
|
|||||||
inst: ref pattern1_0,
|
inst: ref pattern1_0,
|
||||||
result: pattern1_1,
|
result: pattern1_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 468.
|
// Rule at src/prelude.isle line 473.
|
||||||
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
|
||||||
inst: pattern1_0.clone(),
|
inst: pattern1_0.clone(),
|
||||||
};
|
};
|
||||||
@@ -693,7 +694,7 @@ pub fn constructor_consumes_flags_concat<C: Context>(
|
|||||||
result: pattern3_1,
|
result: pattern3_1,
|
||||||
} = pattern2_0
|
} = pattern2_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 475.
|
// Rule at src/prelude.isle line 480.
|
||||||
let expr0_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
let expr0_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
||||||
let expr1_0 = ConsumesFlags::ConsumesFlagsTwiceReturnsValueRegs {
|
let expr1_0 = ConsumesFlags::ConsumesFlagsTwiceReturnsValueRegs {
|
||||||
inst1: pattern1_0.clone(),
|
inst1: pattern1_0.clone(),
|
||||||
@@ -723,7 +724,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
inst: ref pattern3_0,
|
inst: ref pattern3_0,
|
||||||
result: pattern3_1,
|
result: pattern3_1,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 500.
|
// Rule at src/prelude.isle line 505.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::value_reg(ctx, pattern3_1);
|
let expr2_0 = C::value_reg(ctx, pattern3_1);
|
||||||
@@ -734,7 +735,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
inst2: ref pattern3_1,
|
inst2: ref pattern3_1,
|
||||||
result: pattern3_2,
|
result: pattern3_2,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 506.
|
// Rule at src/prelude.isle line 511.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::emit(ctx, pattern3_1);
|
let expr2_0 = C::emit(ctx, pattern3_1);
|
||||||
@@ -747,7 +748,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
inst4: ref pattern3_3,
|
inst4: ref pattern3_3,
|
||||||
result: pattern3_4,
|
result: pattern3_4,
|
||||||
} => {
|
} => {
|
||||||
// Rule at src/prelude.isle line 518.
|
// Rule at src/prelude.isle line 523.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::emit(ctx, pattern3_1);
|
let expr2_0 = C::emit(ctx, pattern3_1);
|
||||||
@@ -768,7 +769,7 @@ pub fn constructor_with_flags<C: Context>(
|
|||||||
result: pattern3_1,
|
result: pattern3_1,
|
||||||
} = pattern2_0
|
} = pattern2_0
|
||||||
{
|
{
|
||||||
// Rule at src/prelude.isle line 494.
|
// Rule at src/prelude.isle line 499.
|
||||||
let expr0_0 = C::emit(ctx, pattern1_0);
|
let expr0_0 = C::emit(ctx, pattern1_0);
|
||||||
let expr1_0 = C::emit(ctx, pattern3_0);
|
let expr1_0 = C::emit(ctx, pattern3_0);
|
||||||
let expr2_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
let expr2_0 = C::value_regs(ctx, pattern1_1, pattern3_1);
|
||||||
@@ -788,7 +789,7 @@ pub fn constructor_with_flags_reg<C: Context>(
|
|||||||
) -> Option<Reg> {
|
) -> Option<Reg> {
|
||||||
let pattern0_0 = arg0;
|
let pattern0_0 = arg0;
|
||||||
let pattern1_0 = arg1;
|
let pattern1_0 = arg1;
|
||||||
// Rule at src/prelude.isle line 535.
|
// Rule at src/prelude.isle line 540.
|
||||||
let expr0_0 = constructor_with_flags(ctx, pattern0_0, pattern1_0)?;
|
let expr0_0 = constructor_with_flags(ctx, pattern0_0, pattern1_0)?;
|
||||||
let expr1_0: usize = 0;
|
let expr1_0: usize = 0;
|
||||||
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ macro_rules! isle_prelude_methods {
|
|||||||
self.lower_ctx.put_value_in_regs(val)
|
self.lower_ctx.put_value_in_regs(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn ensure_in_vreg(&mut self, reg: Reg, ty: Type) -> Reg {
|
||||||
|
self.lower_ctx.ensure_in_vreg(reg, ty)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn value_regs_get(&mut self, regs: ValueRegs, i: usize) -> Reg {
|
fn value_regs_get(&mut self, regs: ValueRegs, i: usize) -> Reg {
|
||||||
regs.regs()[i]
|
regs.regs()[i]
|
||||||
|
|||||||
@@ -129,6 +129,11 @@
|
|||||||
(decl put_in_regs (Value) ValueRegs)
|
(decl put_in_regs (Value) ValueRegs)
|
||||||
(extern constructor put_in_regs put_in_regs)
|
(extern constructor put_in_regs put_in_regs)
|
||||||
|
|
||||||
|
;; If the given reg is a real register, cause the value in reg to be in a virtual
|
||||||
|
;; reg, by copying it into a new virtual reg.
|
||||||
|
(decl ensure_in_vreg (Reg Type) Reg)
|
||||||
|
(extern constructor ensure_in_vreg ensure_in_vreg)
|
||||||
|
|
||||||
;; Get the `n`th register inside a `ValueRegs`.
|
;; Get the `n`th register inside a `ValueRegs`.
|
||||||
(decl value_regs_get (ValueRegs usize) Reg)
|
(decl value_regs_get (ValueRegs usize) Reg)
|
||||||
(extern constructor value_regs_get value_regs_get)
|
(extern constructor value_regs_get value_regs_get)
|
||||||
|
|||||||
@@ -41,6 +41,50 @@ block0(v0: i64, v1: i8):
|
|||||||
; ldaddalb w1, w4, [x0]
|
; ldaddalb w1, w4, [x0]
|
||||||
; ret
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i64(i64, i64) {
|
||||||
|
block0(v0: i64, v1: i64):
|
||||||
|
v2 = atomic_rmw.i64 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; block0:
|
||||||
|
; sub x4, xzr, x1
|
||||||
|
; ldaddal x4, x6, [x0]
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i32(i64, i32) {
|
||||||
|
block0(v0: i64, v1: i32):
|
||||||
|
v2 = atomic_rmw.i32 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; block0:
|
||||||
|
; sub w4, wzr, w1
|
||||||
|
; ldaddal w4, w6, [x0]
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i16(i64, i16) {
|
||||||
|
block0(v0: i64, v1: i16):
|
||||||
|
v2 = atomic_rmw.i16 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; block0:
|
||||||
|
; sub w4, wzr, w1
|
||||||
|
; ldaddalh w4, w6, [x0]
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i8(i64, i8) {
|
||||||
|
block0(v0: i64, v1: i8):
|
||||||
|
v2 = atomic_rmw.i8 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; block0:
|
||||||
|
; sub w4, wzr, w1
|
||||||
|
; ldaddalb w4, w6, [x0]
|
||||||
|
; ret
|
||||||
|
|
||||||
function %atomic_rmw_and_i64(i64, i64) {
|
function %atomic_rmw_and_i64(i64, i64) {
|
||||||
block0(v0: i64, v1: i64):
|
block0(v0: i64, v1: i64):
|
||||||
v2 = atomic_rmw.i64 and v0, v1
|
v2 = atomic_rmw.i64 and v0, v1
|
||||||
@@ -48,7 +92,8 @@ block0(v0: i64, v1: i64):
|
|||||||
}
|
}
|
||||||
|
|
||||||
; block0:
|
; block0:
|
||||||
; ldclral x1, x4, [x0]
|
; eon x4, x1, xzr
|
||||||
|
; ldclral x4, x6, [x0]
|
||||||
; ret
|
; ret
|
||||||
|
|
||||||
function %atomic_rmw_and_i32(i64, i32) {
|
function %atomic_rmw_and_i32(i64, i32) {
|
||||||
@@ -58,7 +103,8 @@ block0(v0: i64, v1: i32):
|
|||||||
}
|
}
|
||||||
|
|
||||||
; block0:
|
; block0:
|
||||||
; ldclral w1, w4, [x0]
|
; eon w4, w1, wzr
|
||||||
|
; ldclral w4, w6, [x0]
|
||||||
; ret
|
; ret
|
||||||
|
|
||||||
function %atomic_rmw_and_i16(i64, i16) {
|
function %atomic_rmw_and_i16(i64, i16) {
|
||||||
@@ -68,7 +114,8 @@ block0(v0: i64, v1: i16):
|
|||||||
}
|
}
|
||||||
|
|
||||||
; block0:
|
; block0:
|
||||||
; ldclralh w1, w4, [x0]
|
; eon w4, w1, wzr
|
||||||
|
; ldclralh w4, w6, [x0]
|
||||||
; ret
|
; ret
|
||||||
|
|
||||||
function %atomic_rmw_and_i8(i64, i8) {
|
function %atomic_rmw_and_i8(i64, i8) {
|
||||||
@@ -78,7 +125,8 @@ block0(v0: i64, v1: i8):
|
|||||||
}
|
}
|
||||||
|
|
||||||
; block0:
|
; block0:
|
||||||
; ldclralb w1, w4, [x0]
|
; eon w4, w1, wzr
|
||||||
|
; ldclralb w4, w6, [x0]
|
||||||
; ret
|
; ret
|
||||||
|
|
||||||
function %atomic_rmw_nand_i64(i64, i64) {
|
function %atomic_rmw_nand_i64(i64, i64) {
|
||||||
|
|||||||
@@ -89,6 +89,94 @@ block0(v0: i64, v1: i8):
|
|||||||
; ldp fp, lr, [sp], #16
|
; ldp fp, lr, [sp], #16
|
||||||
; ret
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i64(i64, i64) {
|
||||||
|
block0(v0: i64, v1: i64):
|
||||||
|
v2 = atomic_rmw.i64 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; stp fp, lr, [sp, #-16]!
|
||||||
|
; mov fp, sp
|
||||||
|
; str x28, [sp, #-16]!
|
||||||
|
; stp x26, x27, [sp, #-16]!
|
||||||
|
; stp x24, x25, [sp, #-16]!
|
||||||
|
; block0:
|
||||||
|
; mov x25, x0
|
||||||
|
; mov x4, x1
|
||||||
|
; mov x26, x4
|
||||||
|
; 1: ldaxr x27, [x25]; sub x28, x27, x26; stlxr w24, x28, [x25]; cbnz w24, 1b
|
||||||
|
; ldp x24, x25, [sp], #16
|
||||||
|
; ldp x26, x27, [sp], #16
|
||||||
|
; ldr x28, [sp], #16
|
||||||
|
; ldp fp, lr, [sp], #16
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i32(i64, i32) {
|
||||||
|
block0(v0: i64, v1: i32):
|
||||||
|
v2 = atomic_rmw.i32 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; stp fp, lr, [sp, #-16]!
|
||||||
|
; mov fp, sp
|
||||||
|
; str x28, [sp, #-16]!
|
||||||
|
; stp x26, x27, [sp, #-16]!
|
||||||
|
; stp x24, x25, [sp, #-16]!
|
||||||
|
; block0:
|
||||||
|
; mov x25, x0
|
||||||
|
; mov x4, x1
|
||||||
|
; mov x26, x4
|
||||||
|
; 1: ldaxr w27, [x25]; sub w28, w27, w26; stlxr w24, w28, [x25]; cbnz w24, 1b
|
||||||
|
; ldp x24, x25, [sp], #16
|
||||||
|
; ldp x26, x27, [sp], #16
|
||||||
|
; ldr x28, [sp], #16
|
||||||
|
; ldp fp, lr, [sp], #16
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i16(i64, i16) {
|
||||||
|
block0(v0: i64, v1: i16):
|
||||||
|
v2 = atomic_rmw.i16 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; stp fp, lr, [sp, #-16]!
|
||||||
|
; mov fp, sp
|
||||||
|
; str x28, [sp, #-16]!
|
||||||
|
; stp x26, x27, [sp, #-16]!
|
||||||
|
; stp x24, x25, [sp, #-16]!
|
||||||
|
; block0:
|
||||||
|
; mov x25, x0
|
||||||
|
; mov x4, x1
|
||||||
|
; mov x26, x4
|
||||||
|
; 1: ldaxrh w27, [x25]; sub w28, w27, w26; stlxrh w24, w28, [x25]; cbnz w24, 1b
|
||||||
|
; ldp x24, x25, [sp], #16
|
||||||
|
; ldp x26, x27, [sp], #16
|
||||||
|
; ldr x28, [sp], #16
|
||||||
|
; ldp fp, lr, [sp], #16
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_i8(i64, i8) {
|
||||||
|
block0(v0: i64, v1: i8):
|
||||||
|
v2 = atomic_rmw.i8 sub v0, v1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
; stp fp, lr, [sp, #-16]!
|
||||||
|
; mov fp, sp
|
||||||
|
; str x28, [sp, #-16]!
|
||||||
|
; stp x26, x27, [sp, #-16]!
|
||||||
|
; stp x24, x25, [sp, #-16]!
|
||||||
|
; block0:
|
||||||
|
; mov x25, x0
|
||||||
|
; mov x4, x1
|
||||||
|
; mov x26, x4
|
||||||
|
; 1: ldaxrb w27, [x25]; sub w28, w27, w26; stlxrb w24, w28, [x25]; cbnz w24, 1b
|
||||||
|
; ldp x24, x25, [sp], #16
|
||||||
|
; ldp x26, x27, [sp], #16
|
||||||
|
; ldr x28, [sp], #16
|
||||||
|
; ldp fp, lr, [sp], #16
|
||||||
|
; ret
|
||||||
|
|
||||||
function %atomic_rmw_and_i64(i64, i64) {
|
function %atomic_rmw_and_i64(i64, i64) {
|
||||||
block0(v0: i64, v1: i64):
|
block0(v0: i64, v1: i64):
|
||||||
v2 = atomic_rmw.i64 and v0, v1
|
v2 = atomic_rmw.i64 and v0, v1
|
||||||
@@ -500,7 +588,7 @@ block0(v0: i64, v1: i16):
|
|||||||
; mov x25, x0
|
; mov x25, x0
|
||||||
; mov x4, x1
|
; mov x4, x1
|
||||||
; mov x26, x4
|
; mov x26, x4
|
||||||
; 1: ldaxrh w27, [x25]; cmp w27, w26; csel w28, w27, w26, gt; stlxrh w24, w28, [x25]; cbnz w24, 1b
|
; 1: ldaxrh w27, [x25]; sxth w27, w27; cmp w27, w26, sxth; csel w28, w27, w26, gt; stlxrh w24, w28, [x25]; cbnz w24, 1b
|
||||||
; ldp x24, x25, [sp], #16
|
; ldp x24, x25, [sp], #16
|
||||||
; ldp x26, x27, [sp], #16
|
; ldp x26, x27, [sp], #16
|
||||||
; ldr x28, [sp], #16
|
; ldr x28, [sp], #16
|
||||||
@@ -522,7 +610,7 @@ block0(v0: i64, v1: i8):
|
|||||||
; mov x25, x0
|
; mov x25, x0
|
||||||
; mov x4, x1
|
; mov x4, x1
|
||||||
; mov x26, x4
|
; mov x26, x4
|
||||||
; 1: ldaxrb w27, [x25]; cmp w27, w26; csel w28, w27, w26, gt; stlxrb w24, w28, [x25]; cbnz w24, 1b
|
; 1: ldaxrb w27, [x25]; sxtb w27, w27; cmp w27, w26, sxtb; csel w28, w27, w26, gt; stlxrb w24, w28, [x25]; cbnz w24, 1b
|
||||||
; ldp x24, x25, [sp], #16
|
; ldp x24, x25, [sp], #16
|
||||||
; ldp x26, x27, [sp], #16
|
; ldp x26, x27, [sp], #16
|
||||||
; ldr x28, [sp], #16
|
; ldr x28, [sp], #16
|
||||||
@@ -676,7 +764,7 @@ block0(v0: i64, v1: i16):
|
|||||||
; mov x25, x0
|
; mov x25, x0
|
||||||
; mov x4, x1
|
; mov x4, x1
|
||||||
; mov x26, x4
|
; mov x26, x4
|
||||||
; 1: ldaxrh w27, [x25]; cmp w27, w26; csel w28, w27, w26, lt; stlxrh w24, w28, [x25]; cbnz w24, 1b
|
; 1: ldaxrh w27, [x25]; sxth w27, w27; cmp w27, w26, sxth; csel w28, w27, w26, lt; stlxrh w24, w28, [x25]; cbnz w24, 1b
|
||||||
; ldp x24, x25, [sp], #16
|
; ldp x24, x25, [sp], #16
|
||||||
; ldp x26, x27, [sp], #16
|
; ldp x26, x27, [sp], #16
|
||||||
; ldr x28, [sp], #16
|
; ldr x28, [sp], #16
|
||||||
@@ -698,7 +786,7 @@ block0(v0: i64, v1: i8):
|
|||||||
; mov x25, x0
|
; mov x25, x0
|
||||||
; mov x4, x1
|
; mov x4, x1
|
||||||
; mov x26, x4
|
; mov x26, x4
|
||||||
; 1: ldaxrb w27, [x25]; cmp w27, w26; csel w28, w27, w26, lt; stlxrb w24, w28, [x25]; cbnz w24, 1b
|
; 1: ldaxrb w27, [x25]; sxtb w27, w27; cmp w27, w26, sxtb; csel w28, w27, w26, lt; stlxrb w24, w28, [x25]; cbnz w24, 1b
|
||||||
; ldp x24, x25, [sp], #16
|
; ldp x24, x25, [sp], #16
|
||||||
; ldp x26, x27, [sp], #16
|
; ldp x26, x27, [sp], #16
|
||||||
; ldr x28, [sp], #16
|
; ldr x28, [sp], #16
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function %atomic_cas_i32(i32, i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32, v2: i32):
|
block0(v0: i32, v1: i32, v2: i32):
|
||||||
v3 = stack_addr.i32 ss0
|
v3 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v3
|
store.i32 little v0, v3
|
||||||
|
|
||||||
v4 = atomic_cas.i32 little v3, v1, v2
|
v4 = atomic_cas.i32 little v3, v1, v2
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
test run
|
||||||
|
target s390x
|
||||||
|
|
||||||
|
; We can't test that these instructions are right regarding atomicity, but we can
|
||||||
|
; test if they perform their operation correctly
|
||||||
|
|
||||||
|
function %atomic_cas_big_i16(i32, i64, i16, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16, v3: i16):
|
||||||
|
v4 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v4
|
||||||
|
|
||||||
|
v5 = iadd.i64 v4, v1
|
||||||
|
v6 = atomic_cas.i16 big v5, v2, v3
|
||||||
|
|
||||||
|
v7 = load.i32 big v4
|
||||||
|
return v7
|
||||||
|
}
|
||||||
|
; run: %atomic_cas_big_i16(0x12345678, 0, 0x1234, 0xabcd) == 0xabcd5678
|
||||||
|
; run: %atomic_cas_big_i16(0x12345678, 0, 0x4321, 0xabcd) == 0x12345678
|
||||||
|
; run: %atomic_cas_big_i16(0x12345678, 2, 0x5678, 0xabcd) == 0x1234abcd
|
||||||
|
; run: %atomic_cas_big_i16(0x12345678, 2, 0x8765, 0xabcd) == 0x12345678
|
||||||
|
|
||||||
|
function %atomic_cas_big_i8(i32, i64, i8, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8, v3: i8):
|
||||||
|
v4 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v4
|
||||||
|
|
||||||
|
v5 = iadd.i64 v4, v1
|
||||||
|
v6 = atomic_cas.i8 big v5, v2, v3
|
||||||
|
|
||||||
|
v7 = load.i32 big v4
|
||||||
|
return v7
|
||||||
|
}
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 0, 0x12, 0xab) == 0xab345678
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 0, 0x21, 0xab) == 0x12345678
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 1, 0x34, 0xab) == 0x12ab5678
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 1, 0x43, 0xab) == 0x12345678
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 2, 0x56, 0xab) == 0x1234ab78
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 2, 0x65, 0xab) == 0x12345678
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 3, 0x78, 0xab) == 0x123456ab
|
||||||
|
; run: %atomic_cas_big_i8(0x12345678, 3, 0x87, 0xab) == 0x12345678
|
||||||
|
|
||||||
@@ -1,27 +1,12 @@
|
|||||||
test run
|
test run
|
||||||
target s390x
|
target s390x
|
||||||
|
target aarch64
|
||||||
|
target aarch64 has_lse
|
||||||
|
target x86_64
|
||||||
|
|
||||||
; We can't test that these instructions are right regarding atomicity, but we can
|
; We can't test that these instructions are right regarding atomicity, but we can
|
||||||
; test if they perform their operation correctly
|
; test if they perform their operation correctly
|
||||||
|
|
||||||
function %atomic_cas_big_i16(i32, i64, i16, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16, v3: i16):
|
|
||||||
v4 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v4
|
|
||||||
|
|
||||||
v5 = iadd.i64 v4, v1
|
|
||||||
v6 = atomic_cas.i16 big v5, v2, v3
|
|
||||||
|
|
||||||
v7 = load.i32 big v4
|
|
||||||
return v7
|
|
||||||
}
|
|
||||||
; run: %atomic_cas_big_i16(0x12345678, 0, 0x1234, 0xabcd) == 0xabcd5678
|
|
||||||
; run: %atomic_cas_big_i16(0x12345678, 0, 0x4321, 0xabcd) == 0x12345678
|
|
||||||
; run: %atomic_cas_big_i16(0x12345678, 2, 0x5678, 0xabcd) == 0x1234abcd
|
|
||||||
; run: %atomic_cas_big_i16(0x12345678, 2, 0x8765, 0xabcd) == 0x12345678
|
|
||||||
|
|
||||||
function %atomic_cas_little_i16(i32, i64, i16, i16) -> i32 {
|
function %atomic_cas_little_i16(i32, i64, i16, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -40,28 +25,6 @@ block0(v0: i32, v1: i64, v2: i16, v3: i16):
|
|||||||
; run: %atomic_cas_little_i16(0x12345678, 0, 0x5678, 0xabcd) == 0x1234abcd
|
; run: %atomic_cas_little_i16(0x12345678, 0, 0x5678, 0xabcd) == 0x1234abcd
|
||||||
; run: %atomic_cas_little_i16(0x12345678, 0, 0x8765, 0xabcd) == 0x12345678
|
; run: %atomic_cas_little_i16(0x12345678, 0, 0x8765, 0xabcd) == 0x12345678
|
||||||
|
|
||||||
function %atomic_cas_big_i8(i32, i64, i8, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8, v3: i8):
|
|
||||||
v4 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v4
|
|
||||||
|
|
||||||
v5 = iadd.i64 v4, v1
|
|
||||||
v6 = atomic_cas.i8 big v5, v2, v3
|
|
||||||
|
|
||||||
v7 = load.i32 big v4
|
|
||||||
return v7
|
|
||||||
}
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 0, 0x12, 0xab) == 0xab345678
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 0, 0x21, 0xab) == 0x12345678
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 1, 0x34, 0xab) == 0x12ab5678
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 1, 0x43, 0xab) == 0x12345678
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 2, 0x56, 0xab) == 0x1234ab78
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 2, 0x65, 0xab) == 0x12345678
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 3, 0x78, 0xab) == 0x123456ab
|
|
||||||
; run: %atomic_cas_big_i8(0x12345678, 3, 0x87, 0xab) == 0x12345678
|
|
||||||
|
|
||||||
function %atomic_cas_little_i8(i32, i64, i8, i8) -> i32 {
|
function %atomic_cas_little_i8(i32, i64, i8, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ function %atomic_cas_i32(i32, i32, i32) -> i32 {
|
|||||||
block0(v0: i32, v1: i32, v2: i32):
|
block0(v0: i32, v1: i32, v2: i32):
|
||||||
stack_store.i32 v0, ss0
|
stack_store.i32 v0, ss0
|
||||||
|
|
||||||
v3 = stack_addr.i32 ss0
|
v3 = stack_addr.i64 ss0
|
||||||
v4 = atomic_cas.i32 v3, v1, v2
|
v4 = atomic_cas.i32 v3, v1, v2
|
||||||
|
|
||||||
v5 = stack_load.i32 ss0
|
v5 = stack_load.i32 ss0
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
test run
|
test run
|
||||||
target s390x
|
target s390x
|
||||||
|
target aarch64
|
||||||
|
target aarch64 has_lse
|
||||||
|
target x86_64
|
||||||
|
|
||||||
; We can't test that these instructions are right regarding atomicity, but we can
|
; We can't test that these instructions are right regarding atomicity, but we can
|
||||||
; test if they perform their operation correctly
|
; test if they perform their operation correctly
|
||||||
@@ -26,7 +29,7 @@ function %atomic_rmw_add_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little add v2, v1
|
v3 = atomic_rmw.i32 little add v2, v1
|
||||||
@@ -64,7 +67,7 @@ function %atomic_rmw_sub_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little sub v2, v1
|
v3 = atomic_rmw.i32 little sub v2, v1
|
||||||
@@ -102,7 +105,7 @@ function %atomic_rmw_and_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little and v2, v1
|
v3 = atomic_rmw.i32 little and v2, v1
|
||||||
@@ -141,7 +144,7 @@ function %atomic_rmw_or_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little or v2, v1
|
v3 = atomic_rmw.i32 little or v2, v1
|
||||||
@@ -180,7 +183,7 @@ function %atomic_rmw_xor_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little xor v2, v1
|
v3 = atomic_rmw.i32 little xor v2, v1
|
||||||
@@ -218,7 +221,7 @@ function %atomic_rmw_nand_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little nand v2, v1
|
v3 = atomic_rmw.i32 little nand v2, v1
|
||||||
@@ -257,7 +260,7 @@ function %atomic_rmw_umin_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little umin v2, v1
|
v3 = atomic_rmw.i32 little umin v2, v1
|
||||||
@@ -297,7 +300,7 @@ function %atomic_rmw_umax_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little umax v2, v1
|
v3 = atomic_rmw.i32 little umax v2, v1
|
||||||
@@ -337,7 +340,7 @@ function %atomic_rmw_smin_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little smin v2, v1
|
v3 = atomic_rmw.i32 little smin v2, v1
|
||||||
@@ -377,7 +380,7 @@ function %atomic_rmw_smax_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little smax v2, v1
|
v3 = atomic_rmw.i32 little smax v2, v1
|
||||||
@@ -415,7 +418,7 @@ function %atomic_rmw_xchg_i32(i32, i32) -> i32 {
|
|||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
block0(v0: i32, v1: i32):
|
||||||
v2 = stack_addr.i32 ss0
|
v2 = stack_addr.i64 ss0
|
||||||
store.i32 little v0, v2
|
store.i32 little v0, v2
|
||||||
|
|
||||||
v3 = atomic_rmw.i32 little xchg v2, v1
|
v3 = atomic_rmw.i32 little xchg v2, v1
|
||||||
|
|||||||
@@ -0,0 +1,460 @@
|
|||||||
|
test run
|
||||||
|
target s390x
|
||||||
|
|
||||||
|
; We can't test that these instructions are right regarding atomicity, but we can
|
||||||
|
; test if they perform their operation correctly
|
||||||
|
|
||||||
|
function %atomic_rmw_add_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big add v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0x1111) == 0x23455678
|
||||||
|
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0xffff) == 0x12335678
|
||||||
|
; run: %atomic_rmw_add_little_i16(0x12345678, 2, 0x1111) == 0x12346789
|
||||||
|
; run: %atomic_rmw_add_little_i16(0x12345678, 2, 0xffff) == 0x12345677
|
||||||
|
|
||||||
|
function %atomic_rmw_add_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big add v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 0, 0x11) == 0x23345678
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 0, 0xff) == 0x11345678
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 1, 0x11) == 0x12455678
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 1, 0xff) == 0x12335678
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 2, 0x11) == 0x12346778
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 2, 0xff) == 0x12345578
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 3, 0x11) == 0x12345689
|
||||||
|
; run: %atomic_rmw_add_big_i8(0x12345678, 3, 0xff) == 0x12345677
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big sub v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_sub_big_i16(0x12345678, 0, 0x1111) == 0x01235678
|
||||||
|
; run: %atomic_rmw_sub_big_i16(0x12345678, 0, 0xffff) == 0x12355678
|
||||||
|
; run: %atomic_rmw_sub_big_i16(0x12345678, 2, 0x1111) == 0x12344567
|
||||||
|
; run: %atomic_rmw_sub_big_i16(0x12345678, 2, 0xffff) == 0x12345679
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_sub_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big sub v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 0, 0x11) == 0x01345678
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 0, 0xff) == 0x13345678
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 1, 0x11) == 0x12235678
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 1, 0xff) == 0x12355678
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 2, 0x11) == 0x12344578
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 2, 0xff) == 0x12345778
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 3, 0x11) == 0x12345667
|
||||||
|
; run: %atomic_rmw_sub_big_i8(0x12345678, 3, 0xff) == 0x12345679
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_and_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big and v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_and_big_i16(0x12345678, 0, 0xf000) == 0x10005678
|
||||||
|
; run: %atomic_rmw_and_big_i16(0x12345678, 0, 0x000f) == 0x00045678
|
||||||
|
; run: %atomic_rmw_and_big_i16(0x12345678, 2, 0xf000) == 0x12345000
|
||||||
|
; run: %atomic_rmw_and_big_i16(0x12345678, 2, 0x000f) == 0x12340008
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_and_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big and v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 0, 0xf0) == 0x10345678
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 0, 0x0f) == 0x02345678
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 1, 0xf0) == 0x12305678
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 1, 0x0f) == 0x12045678
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 2, 0xf0) == 0x12345078
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 2, 0x0f) == 0x12340678
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 3, 0xf0) == 0x12345670
|
||||||
|
; run: %atomic_rmw_and_big_i8(0x12345678, 3, 0x0f) == 0x12345608
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_or_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big or v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_or_big_i16(0x12345678, 0, 0xf000) == 0xf2345678
|
||||||
|
; run: %atomic_rmw_or_big_i16(0x12345678, 0, 0x000f) == 0x123f5678
|
||||||
|
; run: %atomic_rmw_or_big_i16(0x12345678, 2, 0xf000) == 0x1234f678
|
||||||
|
; run: %atomic_rmw_or_big_i16(0x12345678, 2, 0x000f) == 0x1234567f
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_or_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big or v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 0, 0xf0) == 0xf2345678
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 0, 0x0f) == 0x1f345678
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 1, 0xf0) == 0x12f45678
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 1, 0x0f) == 0x123f5678
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 2, 0xf0) == 0x1234f678
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 2, 0x0f) == 0x12345f78
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 3, 0xf0) == 0x123456f8
|
||||||
|
; run: %atomic_rmw_or_big_i8(0x12345678, 3, 0x0f) == 0x1234567f
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_xor_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big xor v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_xor_big_i16(0x12345678, 0, 0xf000) == 0xe2345678
|
||||||
|
; run: %atomic_rmw_xor_big_i16(0x12345678, 0, 0x000f) == 0x123b5678
|
||||||
|
; run: %atomic_rmw_xor_big_i16(0x12345678, 2, 0xf000) == 0x1234a678
|
||||||
|
; run: %atomic_rmw_xor_big_i16(0x12345678, 2, 0x000f) == 0x12345677
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_xor_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big xor v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 0, 0xf0) == 0xe2345678
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 0, 0x0f) == 0x1d345678
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 1, 0xf0) == 0x12c45678
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 1, 0x0f) == 0x123b5678
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 2, 0xf0) == 0x1234a678
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 2, 0x0f) == 0x12345978
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 3, 0xf0) == 0x12345688
|
||||||
|
; run: %atomic_rmw_xor_big_i8(0x12345678, 3, 0x0f) == 0x12345677
|
||||||
|
|
||||||
|
function %atomic_rmw_nand_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big nand v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_nand_big_i16(0x12345678, 0, 0xf000) == 0xefff5678
|
||||||
|
; run: %atomic_rmw_nand_big_i16(0x12345678, 0, 0x000f) == 0xfffb5678
|
||||||
|
; run: %atomic_rmw_nand_big_i16(0x12345678, 2, 0xf000) == 0x1234afff
|
||||||
|
; run: %atomic_rmw_nand_big_i16(0x12345678, 2, 0x000f) == 0x1234fff7
|
||||||
|
|
||||||
|
function %atomic_rmw_nand_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big nand v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 0, 0xf0) == 0xef345678
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 0, 0x0f) == 0xfd345678
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 1, 0xf0) == 0x12cf5678
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 1, 0x0f) == 0x12fb5678
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 2, 0xf0) == 0x1234af78
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 2, 0x0f) == 0x1234f978
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 3, 0xf0) == 0x1234568f
|
||||||
|
; run: %atomic_rmw_nand_big_i8(0x12345678, 3, 0x0f) == 0x123456f7
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_umin_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big umin v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_umin_big_i16(0x12345678, 0, 0x1111) == 0x11115678
|
||||||
|
; run: %atomic_rmw_umin_big_i16(0x12345678, 0, 0xffff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umin_big_i16(0x12345678, 2, 0x1111) == 0x12341111
|
||||||
|
; run: %atomic_rmw_umin_big_i16(0x12345678, 2, 0xffff) == 0x12345678
|
||||||
|
|
||||||
|
function %atomic_rmw_umin_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big umin v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 0, 0x11) == 0x11345678
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 0, 0xff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 1, 0x11) == 0x12115678
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 1, 0xff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 2, 0x11) == 0x12341178
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 2, 0xff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 3, 0x11) == 0x12345611
|
||||||
|
; run: %atomic_rmw_umin_big_i8(0x12345678, 3, 0xff) == 0x12345678
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_umax_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big umax v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_umax_big_i16(0x12345678, 0, 0x1111) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umax_big_i16(0x12345678, 0, 0xffff) == 0xffff5678
|
||||||
|
; run: %atomic_rmw_umax_big_i16(0x12345678, 2, 0x1111) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umax_big_i16(0x12345678, 2, 0xffff) == 0x1234ffff
|
||||||
|
|
||||||
|
function %atomic_rmw_umax_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big umax v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 0, 0x11) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 0, 0xff) == 0xff345678
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 1, 0x11) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 1, 0xff) == 0x12ff5678
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 2, 0x11) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 2, 0xff) == 0x1234ff78
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 3, 0x11) == 0x12345678
|
||||||
|
; run: %atomic_rmw_umax_big_i8(0x12345678, 3, 0xff) == 0x123456ff
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_smin_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big smin v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_smin_big_i16(0x12345678, 0, 0x1111) == 0x11115678
|
||||||
|
; run: %atomic_rmw_smin_big_i16(0x12345678, 0, 0xffff) == 0xffff5678
|
||||||
|
; run: %atomic_rmw_smin_big_i16(0x12345678, 2, 0x1111) == 0x12341111
|
||||||
|
; run: %atomic_rmw_smin_big_i16(0x12345678, 2, 0xffff) == 0x1234ffff
|
||||||
|
|
||||||
|
function %atomic_rmw_smin_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big smin v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 0, 0x11) == 0x11345678
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 0, 0xff) == 0xff345678
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 1, 0x11) == 0x12115678
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 1, 0xff) == 0x12ff5678
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 2, 0x11) == 0x12341178
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 2, 0xff) == 0x1234ff78
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 3, 0x11) == 0x12345611
|
||||||
|
; run: %atomic_rmw_smin_big_i8(0x12345678, 3, 0xff) == 0x123456ff
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_smax_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big smax v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_smax_big_i16(0x12345678, 0, 0xffff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_smax_big_i16(0x12345678, 0, 0x7fff) == 0x7fff5678
|
||||||
|
; run: %atomic_rmw_smax_big_i16(0x12345678, 2, 0xffff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_smax_big_i16(0x12345678, 2, 0x7fff) == 0x12347fff
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_smax_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big smax v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 0, 0xff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 0, 0x7f) == 0x7f345678
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 1, 0xff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 1, 0x7f) == 0x127f5678
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 2, 0xff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 2, 0x7f) == 0x12347f78
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 3, 0xff) == 0x12345678
|
||||||
|
; run: %atomic_rmw_smax_big_i8(0x12345678, 3, 0x7f) == 0x1234567f
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_xchg_big_i16(i32, i64, i16) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i16):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i16 big xchg v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0x1111) == 0x11115678
|
||||||
|
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0xffff) == 0xffff5678
|
||||||
|
; run: %atomic_rmw_xchg_little_i16(0x12345678, 2, 0x1111) == 0x12341111
|
||||||
|
; run: %atomic_rmw_xchg_little_i16(0x12345678, 2, 0xffff) == 0x1234ffff
|
||||||
|
|
||||||
|
|
||||||
|
function %atomic_rmw_xchg_big_i8(i32, i64, i8) -> i32 {
|
||||||
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
|
block0(v0: i32, v1: i64, v2: i8):
|
||||||
|
v3 = stack_addr.i64 ss0
|
||||||
|
store.i32 big v0, v3
|
||||||
|
|
||||||
|
v4 = iadd.i64 v3, v1
|
||||||
|
v5 = atomic_rmw.i8 big xchg v4, v2
|
||||||
|
|
||||||
|
v6 = load.i32 big v3
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 0, 0x11) == 0x11345678
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 0, 0xff) == 0xff345678
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 1, 0x11) == 0x12115678
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 1, 0xff) == 0x12ff5678
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 2, 0x11) == 0x12341178
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 2, 0xff) == 0x1234ff78
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 3, 0x11) == 0x12345611
|
||||||
|
; run: %atomic_rmw_xchg_big_i8(0x12345678, 3, 0xff) == 0x123456ff
|
||||||
|
|
||||||
@@ -1,27 +1,12 @@
|
|||||||
test run
|
test run
|
||||||
target s390x
|
target s390x
|
||||||
|
target aarch64
|
||||||
|
target aarch64 has_lse
|
||||||
|
target x86_64
|
||||||
|
|
||||||
; We can't test that these instructions are right regarding atomicity, but we can
|
; We can't test that these instructions are right regarding atomicity, but we can
|
||||||
; test if they perform their operation correctly
|
; test if they perform their operation correctly
|
||||||
|
|
||||||
function %atomic_rmw_add_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big add v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0x1111) == 0x23455678
|
|
||||||
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0xffff) == 0x12335678
|
|
||||||
; run: %atomic_rmw_add_little_i16(0x12345678, 2, 0x1111) == 0x12346789
|
|
||||||
; run: %atomic_rmw_add_little_i16(0x12345678, 2, 0xffff) == 0x12345677
|
|
||||||
|
|
||||||
function %atomic_rmw_add_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_add_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -40,28 +25,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0x1111) == 0x12346789
|
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0x1111) == 0x12346789
|
||||||
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0xffff) == 0x12345677
|
; run: %atomic_rmw_add_little_i16(0x12345678, 0, 0xffff) == 0x12345677
|
||||||
|
|
||||||
function %atomic_rmw_add_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big add v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 0, 0x11) == 0x23345678
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 0, 0xff) == 0x11345678
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 1, 0x11) == 0x12455678
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 1, 0xff) == 0x12335678
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 2, 0x11) == 0x12346778
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 2, 0xff) == 0x12345578
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 3, 0x11) == 0x12345689
|
|
||||||
; run: %atomic_rmw_add_big_i8(0x12345678, 3, 0xff) == 0x12345677
|
|
||||||
|
|
||||||
function %atomic_rmw_add_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_add_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -84,26 +47,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_add_little_i8(0x12345678, 0, 0x11) == 0x12345689
|
; run: %atomic_rmw_add_little_i8(0x12345678, 0, 0x11) == 0x12345689
|
||||||
; run: %atomic_rmw_add_little_i8(0x12345678, 0, 0xff) == 0x12345677
|
; run: %atomic_rmw_add_little_i8(0x12345678, 0, 0xff) == 0x12345677
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_sub_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big sub v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_sub_big_i16(0x12345678, 0, 0x1111) == 0x01235678
|
|
||||||
; run: %atomic_rmw_sub_big_i16(0x12345678, 0, 0xffff) == 0x12355678
|
|
||||||
; run: %atomic_rmw_sub_big_i16(0x12345678, 2, 0x1111) == 0x12344567
|
|
||||||
; run: %atomic_rmw_sub_big_i16(0x12345678, 2, 0xffff) == 0x12345679
|
|
||||||
|
|
||||||
function %atomic_rmw_sub_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_sub_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -122,28 +65,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_sub_little_i16(0x12345678, 0, 0x1111) == 0x12344567
|
; run: %atomic_rmw_sub_little_i16(0x12345678, 0, 0x1111) == 0x12344567
|
||||||
; run: %atomic_rmw_sub_little_i16(0x12345678, 0, 0xffff) == 0x12345679
|
; run: %atomic_rmw_sub_little_i16(0x12345678, 0, 0xffff) == 0x12345679
|
||||||
|
|
||||||
function %atomic_rmw_sub_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big sub v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 0, 0x11) == 0x01345678
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 0, 0xff) == 0x13345678
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 1, 0x11) == 0x12235678
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 1, 0xff) == 0x12355678
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 2, 0x11) == 0x12344578
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 2, 0xff) == 0x12345778
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 3, 0x11) == 0x12345667
|
|
||||||
; run: %atomic_rmw_sub_big_i8(0x12345678, 3, 0xff) == 0x12345679
|
|
||||||
|
|
||||||
function %atomic_rmw_sub_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_sub_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -166,26 +87,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_sub_little_i8(0x12345678, 0, 0x11) == 0x12345667
|
; run: %atomic_rmw_sub_little_i8(0x12345678, 0, 0x11) == 0x12345667
|
||||||
; run: %atomic_rmw_sub_little_i8(0x12345678, 0, 0xff) == 0x12345679
|
; run: %atomic_rmw_sub_little_i8(0x12345678, 0, 0xff) == 0x12345679
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_and_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big and v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_and_big_i16(0x12345678, 0, 0xf000) == 0x10005678
|
|
||||||
; run: %atomic_rmw_and_big_i16(0x12345678, 0, 0x000f) == 0x00045678
|
|
||||||
; run: %atomic_rmw_and_big_i16(0x12345678, 2, 0xf000) == 0x12345000
|
|
||||||
; run: %atomic_rmw_and_big_i16(0x12345678, 2, 0x000f) == 0x12340008
|
|
||||||
|
|
||||||
function %atomic_rmw_and_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_and_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -204,28 +105,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_and_little_i16(0x12345678, 0, 0xf000) == 0x12345000
|
; run: %atomic_rmw_and_little_i16(0x12345678, 0, 0xf000) == 0x12345000
|
||||||
; run: %atomic_rmw_and_little_i16(0x12345678, 0, 0x000f) == 0x12340008
|
; run: %atomic_rmw_and_little_i16(0x12345678, 0, 0x000f) == 0x12340008
|
||||||
|
|
||||||
function %atomic_rmw_and_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big and v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 0, 0xf0) == 0x10345678
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 0, 0x0f) == 0x02345678
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 1, 0xf0) == 0x12305678
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 1, 0x0f) == 0x12045678
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 2, 0xf0) == 0x12345078
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 2, 0x0f) == 0x12340678
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 3, 0xf0) == 0x12345670
|
|
||||||
; run: %atomic_rmw_and_big_i8(0x12345678, 3, 0x0f) == 0x12345608
|
|
||||||
|
|
||||||
function %atomic_rmw_and_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_and_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -249,25 +128,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_and_little_i8(0x12345678, 0, 0x0f) == 0x12345608
|
; run: %atomic_rmw_and_little_i8(0x12345678, 0, 0x0f) == 0x12345608
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_or_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big or v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_or_big_i16(0x12345678, 0, 0xf000) == 0xf2345678
|
|
||||||
; run: %atomic_rmw_or_big_i16(0x12345678, 0, 0x000f) == 0x123f5678
|
|
||||||
; run: %atomic_rmw_or_big_i16(0x12345678, 2, 0xf000) == 0x1234f678
|
|
||||||
; run: %atomic_rmw_or_big_i16(0x12345678, 2, 0x000f) == 0x1234567f
|
|
||||||
|
|
||||||
function %atomic_rmw_or_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_or_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -286,28 +146,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_or_little_i16(0x12345678, 0, 0xf000) == 0x1234f678
|
; run: %atomic_rmw_or_little_i16(0x12345678, 0, 0xf000) == 0x1234f678
|
||||||
; run: %atomic_rmw_or_little_i16(0x12345678, 0, 0x000f) == 0x1234567f
|
; run: %atomic_rmw_or_little_i16(0x12345678, 0, 0x000f) == 0x1234567f
|
||||||
|
|
||||||
function %atomic_rmw_or_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big or v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 0, 0xf0) == 0xf2345678
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 0, 0x0f) == 0x1f345678
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 1, 0xf0) == 0x12f45678
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 1, 0x0f) == 0x123f5678
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 2, 0xf0) == 0x1234f678
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 2, 0x0f) == 0x12345f78
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 3, 0xf0) == 0x123456f8
|
|
||||||
; run: %atomic_rmw_or_big_i8(0x12345678, 3, 0x0f) == 0x1234567f
|
|
||||||
|
|
||||||
function %atomic_rmw_or_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_or_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -330,27 +168,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_or_little_i8(0x12345678, 0, 0xf0) == 0x123456f8
|
; run: %atomic_rmw_or_little_i8(0x12345678, 0, 0xf0) == 0x123456f8
|
||||||
; run: %atomic_rmw_or_little_i8(0x12345678, 0, 0x0f) == 0x1234567f
|
; run: %atomic_rmw_or_little_i8(0x12345678, 0, 0x0f) == 0x1234567f
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_xor_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big xor v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xor_big_i16(0x12345678, 0, 0xf000) == 0xe2345678
|
|
||||||
; run: %atomic_rmw_xor_big_i16(0x12345678, 0, 0x000f) == 0x123b5678
|
|
||||||
; run: %atomic_rmw_xor_big_i16(0x12345678, 2, 0xf000) == 0x1234a678
|
|
||||||
; run: %atomic_rmw_xor_big_i16(0x12345678, 2, 0x000f) == 0x12345677
|
|
||||||
|
|
||||||
function %atomic_rmw_xor_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_xor_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -369,28 +186,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_xor_little_i16(0x12345678, 0, 0xf000) == 0x1234a678
|
; run: %atomic_rmw_xor_little_i16(0x12345678, 0, 0xf000) == 0x1234a678
|
||||||
; run: %atomic_rmw_xor_little_i16(0x12345678, 0, 0x000f) == 0x12345677
|
; run: %atomic_rmw_xor_little_i16(0x12345678, 0, 0x000f) == 0x12345677
|
||||||
|
|
||||||
function %atomic_rmw_xor_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big xor v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 0, 0xf0) == 0xe2345678
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 0, 0x0f) == 0x1d345678
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 1, 0xf0) == 0x12c45678
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 1, 0x0f) == 0x123b5678
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 2, 0xf0) == 0x1234a678
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 2, 0x0f) == 0x12345978
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 3, 0xf0) == 0x12345688
|
|
||||||
; run: %atomic_rmw_xor_big_i8(0x12345678, 3, 0x0f) == 0x12345677
|
|
||||||
|
|
||||||
function %atomic_rmw_xor_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_xor_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -414,25 +209,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_xor_little_i8(0x12345678, 0, 0x0f) == 0x12345677
|
; run: %atomic_rmw_xor_little_i8(0x12345678, 0, 0x0f) == 0x12345677
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_nand_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big nand v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_nand_big_i16(0x12345678, 0, 0xf000) == 0xefff5678
|
|
||||||
; run: %atomic_rmw_nand_big_i16(0x12345678, 0, 0x000f) == 0xfffb5678
|
|
||||||
; run: %atomic_rmw_nand_big_i16(0x12345678, 2, 0xf000) == 0x1234afff
|
|
||||||
; run: %atomic_rmw_nand_big_i16(0x12345678, 2, 0x000f) == 0x1234fff7
|
|
||||||
|
|
||||||
function %atomic_rmw_nand_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_nand_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -451,28 +227,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_nand_little_i16(0x12345678, 0, 0xf000) == 0x1234afff
|
; run: %atomic_rmw_nand_little_i16(0x12345678, 0, 0xf000) == 0x1234afff
|
||||||
; run: %atomic_rmw_nand_little_i16(0x12345678, 0, 0x000f) == 0x1234fff7
|
; run: %atomic_rmw_nand_little_i16(0x12345678, 0, 0x000f) == 0x1234fff7
|
||||||
|
|
||||||
function %atomic_rmw_nand_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big nand v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 0, 0xf0) == 0xef345678
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 0, 0x0f) == 0xfd345678
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 1, 0xf0) == 0x12cf5678
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 1, 0x0f) == 0x12fb5678
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 2, 0xf0) == 0x1234af78
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 2, 0x0f) == 0x1234f978
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 3, 0xf0) == 0x1234568f
|
|
||||||
; run: %atomic_rmw_nand_big_i8(0x12345678, 3, 0x0f) == 0x123456f7
|
|
||||||
|
|
||||||
function %atomic_rmw_nand_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_nand_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -496,25 +250,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_nand_little_i8(0x12345678, 0, 0x0f) == 0x123456f7
|
; run: %atomic_rmw_nand_little_i8(0x12345678, 0, 0x0f) == 0x123456f7
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_umin_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big umin v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umin_big_i16(0x12345678, 0, 0x1111) == 0x11115678
|
|
||||||
; run: %atomic_rmw_umin_big_i16(0x12345678, 0, 0xffff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umin_big_i16(0x12345678, 2, 0x1111) == 0x12341111
|
|
||||||
; run: %atomic_rmw_umin_big_i16(0x12345678, 2, 0xffff) == 0x12345678
|
|
||||||
|
|
||||||
function %atomic_rmw_umin_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_umin_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -533,28 +268,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_umin_little_i16(0x12345678, 0, 0x1111) == 0x12341111
|
; run: %atomic_rmw_umin_little_i16(0x12345678, 0, 0x1111) == 0x12341111
|
||||||
; run: %atomic_rmw_umin_little_i16(0x12345678, 0, 0xffff) == 0x12345678
|
; run: %atomic_rmw_umin_little_i16(0x12345678, 0, 0xffff) == 0x12345678
|
||||||
|
|
||||||
function %atomic_rmw_umin_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big umin v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 0, 0x11) == 0x11345678
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 0, 0xff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 1, 0x11) == 0x12115678
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 1, 0xff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 2, 0x11) == 0x12341178
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 2, 0xff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 3, 0x11) == 0x12345611
|
|
||||||
; run: %atomic_rmw_umin_big_i8(0x12345678, 3, 0xff) == 0x12345678
|
|
||||||
|
|
||||||
function %atomic_rmw_umin_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_umin_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -578,25 +291,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_umin_little_i8(0x12345678, 0, 0xff) == 0x12345678
|
; run: %atomic_rmw_umin_little_i8(0x12345678, 0, 0xff) == 0x12345678
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_umax_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big umax v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umax_big_i16(0x12345678, 0, 0x1111) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umax_big_i16(0x12345678, 0, 0xffff) == 0xffff5678
|
|
||||||
; run: %atomic_rmw_umax_big_i16(0x12345678, 2, 0x1111) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umax_big_i16(0x12345678, 2, 0xffff) == 0x1234ffff
|
|
||||||
|
|
||||||
function %atomic_rmw_umax_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_umax_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -615,28 +309,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_umax_little_i16(0x12345678, 0, 0x1111) == 0x12345678
|
; run: %atomic_rmw_umax_little_i16(0x12345678, 0, 0x1111) == 0x12345678
|
||||||
; run: %atomic_rmw_umax_little_i16(0x12345678, 0, 0xffff) == 0x1234ffff
|
; run: %atomic_rmw_umax_little_i16(0x12345678, 0, 0xffff) == 0x1234ffff
|
||||||
|
|
||||||
function %atomic_rmw_umax_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big umax v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 0, 0x11) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 0, 0xff) == 0xff345678
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 1, 0x11) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 1, 0xff) == 0x12ff5678
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 2, 0x11) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 2, 0xff) == 0x1234ff78
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 3, 0x11) == 0x12345678
|
|
||||||
; run: %atomic_rmw_umax_big_i8(0x12345678, 3, 0xff) == 0x123456ff
|
|
||||||
|
|
||||||
function %atomic_rmw_umax_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_umax_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -660,25 +332,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_umax_little_i8(0x12345678, 0, 0xff) == 0x123456ff
|
; run: %atomic_rmw_umax_little_i8(0x12345678, 0, 0xff) == 0x123456ff
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_smin_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big smin v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smin_big_i16(0x12345678, 0, 0x1111) == 0x11115678
|
|
||||||
; run: %atomic_rmw_smin_big_i16(0x12345678, 0, 0xffff) == 0xffff5678
|
|
||||||
; run: %atomic_rmw_smin_big_i16(0x12345678, 2, 0x1111) == 0x12341111
|
|
||||||
; run: %atomic_rmw_smin_big_i16(0x12345678, 2, 0xffff) == 0x1234ffff
|
|
||||||
|
|
||||||
function %atomic_rmw_smin_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_smin_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -697,27 +350,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_smin_little_i16(0x12345678, 0, 0x1111) == 0x12341111
|
; run: %atomic_rmw_smin_little_i16(0x12345678, 0, 0x1111) == 0x12341111
|
||||||
; run: %atomic_rmw_smin_little_i16(0x12345678, 0, 0xffff) == 0x1234ffff
|
; run: %atomic_rmw_smin_little_i16(0x12345678, 0, 0xffff) == 0x1234ffff
|
||||||
|
|
||||||
function %atomic_rmw_smin_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big smin v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 0, 0x11) == 0x11345678
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 0, 0xff) == 0xff345678
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 1, 0x11) == 0x12115678
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 1, 0xff) == 0x12ff5678
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 2, 0x11) == 0x12341178
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 2, 0xff) == 0x1234ff78
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 3, 0x11) == 0x12345611
|
|
||||||
; run: %atomic_rmw_smin_big_i8(0x12345678, 3, 0xff) == 0x123456ff
|
|
||||||
|
|
||||||
function %atomic_rmw_smin_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_smin_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
@@ -742,25 +374,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_smin_little_i8(0x12345678, 0, 0xff) == 0x123456ff
|
; run: %atomic_rmw_smin_little_i8(0x12345678, 0, 0xff) == 0x123456ff
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_smax_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big smax v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smax_big_i16(0x12345678, 0, 0xffff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_smax_big_i16(0x12345678, 0, 0x7fff) == 0x7fff5678
|
|
||||||
; run: %atomic_rmw_smax_big_i16(0x12345678, 2, 0xffff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_smax_big_i16(0x12345678, 2, 0x7fff) == 0x12347fff
|
|
||||||
|
|
||||||
function %atomic_rmw_smax_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_smax_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -779,27 +392,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_smax_little_i16(0x12345678, 0, 0xffff) == 0x12345678
|
; run: %atomic_rmw_smax_little_i16(0x12345678, 0, 0xffff) == 0x12345678
|
||||||
; run: %atomic_rmw_smax_little_i16(0x12345678, 0, 0x7fff) == 0x12347fff
|
; run: %atomic_rmw_smax_little_i16(0x12345678, 0, 0x7fff) == 0x12347fff
|
||||||
|
|
||||||
function %atomic_rmw_smax_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big smax v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 0, 0xff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 0, 0x7f) == 0x7f345678
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 1, 0xff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 1, 0x7f) == 0x127f5678
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 2, 0xff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 2, 0x7f) == 0x12347f78
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 3, 0xff) == 0x12345678
|
|
||||||
; run: %atomic_rmw_smax_big_i8(0x12345678, 3, 0x7f) == 0x1234567f
|
|
||||||
|
|
||||||
function %atomic_rmw_smax_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_smax_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
@@ -824,25 +416,6 @@ block0(v0: i32, v1: i64, v2: i8):
|
|||||||
; run: %atomic_rmw_smax_little_i8(0x12345678, 0, 0x7f) == 0x1234567f
|
; run: %atomic_rmw_smax_little_i8(0x12345678, 0, 0x7f) == 0x1234567f
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_xchg_big_i16(i32, i64, i16) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i16):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i16 big xchg v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0x1111) == 0x11115678
|
|
||||||
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0xffff) == 0xffff5678
|
|
||||||
; run: %atomic_rmw_xchg_little_i16(0x12345678, 2, 0x1111) == 0x12341111
|
|
||||||
; run: %atomic_rmw_xchg_little_i16(0x12345678, 2, 0xffff) == 0x1234ffff
|
|
||||||
|
|
||||||
function %atomic_rmw_xchg_little_i16(i32, i64, i16) -> i32 {
|
function %atomic_rmw_xchg_little_i16(i32, i64, i16) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
|
|
||||||
@@ -861,27 +434,6 @@ block0(v0: i32, v1: i64, v2: i16):
|
|||||||
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0x1111) == 0x12341111
|
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0x1111) == 0x12341111
|
||||||
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0xffff) == 0x1234ffff
|
; run: %atomic_rmw_xchg_little_i16(0x12345678, 0, 0xffff) == 0x1234ffff
|
||||||
|
|
||||||
function %atomic_rmw_xchg_big_i8(i32, i64, i8) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i64, v2: i8):
|
|
||||||
v3 = stack_addr.i64 ss0
|
|
||||||
store.i32 big v0, v3
|
|
||||||
|
|
||||||
v4 = iadd.i64 v3, v1
|
|
||||||
v5 = atomic_rmw.i8 big xchg v4, v2
|
|
||||||
|
|
||||||
v6 = load.i32 big v3
|
|
||||||
return v6
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 0, 0x11) == 0x11345678
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 0, 0xff) == 0xff345678
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 1, 0x11) == 0x12115678
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 1, 0xff) == 0x12ff5678
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 2, 0x11) == 0x12341178
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 2, 0xff) == 0x1234ff78
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 3, 0x11) == 0x12345611
|
|
||||||
; run: %atomic_rmw_xchg_big_i8(0x12345678, 3, 0xff) == 0x123456ff
|
|
||||||
|
|
||||||
function %atomic_rmw_xchg_little_i8(i32, i64, i8) -> i32 {
|
function %atomic_rmw_xchg_little_i8(i32, i64, i8) -> i32 {
|
||||||
ss0 = explicit_slot 4
|
ss0 = explicit_slot 4
|
||||||
@@ -1,432 +0,0 @@
|
|||||||
test run
|
|
||||||
target aarch64
|
|
||||||
target aarch64 has_lse
|
|
||||||
target x86_64
|
|
||||||
target s390x
|
|
||||||
|
|
||||||
; We can't test that these instructions are right regarding atomicity, but we can
|
|
||||||
; test if they perform their operation correctly
|
|
||||||
|
|
||||||
function %atomic_rmw_add_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 add v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_add_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_add_i64(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_add_i64(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_add_i64(1, 1) == 2
|
|
||||||
; run: %atomic_rmw_add_i64(0xC0FFEEEE_C0FFEEEE, 0x1DCB1111_1DCB1111) == 0xDECAFFFF_DECAFFFF
|
|
||||||
|
|
||||||
function %atomic_rmw_add_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 add v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_add_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_add_i32(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_add_i32(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_add_i32(1, 1) == 2
|
|
||||||
; run: %atomic_rmw_add_i32(0xC0FFEEEE, 0x1DCB1111) == 0xDECAFFFF
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_sub_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 sub v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_sub_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_sub_i64(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_sub_i64(0, 1) == -1
|
|
||||||
; run: %atomic_rmw_sub_i64(1, 1) == 0
|
|
||||||
; run: %atomic_rmw_sub_i64(0xDECAFFFF_DECAFFFF, 0x1DCB1111_1DCB1111) == 0xC0FFEEEE_C0FFEEEE
|
|
||||||
|
|
||||||
function %atomic_rmw_sub_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 sub v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_sub_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_sub_i32(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_sub_i32(0, 1) == -1
|
|
||||||
; run: %atomic_rmw_sub_i32(1, 1) == 0
|
|
||||||
; run: %atomic_rmw_sub_i32(0xDECAFFFF, 0x1DCB1111) == 0xC0FFEEEE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_and_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 and v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_and_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_and_i64(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_and_i64(0, 1) == 0
|
|
||||||
; run: %atomic_rmw_and_i64(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_and_i64(0xF1FFFEFE_FEEEFFFF, 0xCEFFEFEF_DFDBFFFF) == 0xC0FFEEEE_DECAFFFF
|
|
||||||
|
|
||||||
function %atomic_rmw_and_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 and v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
|
|
||||||
; run: %atomic_rmw_and_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_and_i64(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_and_i64(0, 1) == 0
|
|
||||||
; run: %atomic_rmw_and_i64(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_and_i64(0xF1FFFEFE, 0xCEFFEFEF) == 0xC0FFEEEE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_or_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 or v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_or_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_or_i64(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_or_i64(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_or_i64(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_or_i64(0x80AAAAAA_8A8AAAAA, 0x40554444_54405555) == 0xC0FFEEEE_DECAFFFF
|
|
||||||
|
|
||||||
function %atomic_rmw_or_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 or v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
|
|
||||||
; run: %atomic_rmw_or_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_or_i32(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_or_i32(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_or_i32(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_or_i32(0x80AAAAAA, 0x40554444) == 0xC0FFEEEE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_xor_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 xor v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xor_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_xor_i64(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_xor_i64(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_xor_i64(1, 1) == 0
|
|
||||||
; run: %atomic_rmw_xor_i64(0x8FA50A64_9440A07D, 0x4F5AE48A_4A8A5F82) == 0xC0FFEEEE_DECAFFFF
|
|
||||||
|
|
||||||
function %atomic_rmw_xor_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 xor v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xor_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_xor_i32(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_xor_i32(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_xor_i32(1, 1) == 0
|
|
||||||
; run: %atomic_rmw_xor_i32(0x8FA50A64, 0x4F5AE48A) == 0xC0FFEEEE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_nand_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 nand v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_nand_i64(0, 0) == -1
|
|
||||||
; run: %atomic_rmw_nand_i64(1, 0) == -1
|
|
||||||
; run: %atomic_rmw_nand_i64(0, 1) == -1
|
|
||||||
; run: %atomic_rmw_nand_i64(1, 1) == -2
|
|
||||||
; run: %atomic_rmw_nand_i64(0xC0FFEEEE_DECAFFFF, 0x7DCB5691_7DCB5691) == 0xBF34B97F_A335A96E
|
|
||||||
|
|
||||||
function %atomic_rmw_nand_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 nand v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_nand_i32(0, 0) == -1
|
|
||||||
; run: %atomic_rmw_nand_i32(1, 0) == -1
|
|
||||||
; run: %atomic_rmw_nand_i32(0, 1) == -1
|
|
||||||
; run: %atomic_rmw_nand_i32(1, 1) == -2
|
|
||||||
; run: %atomic_rmw_nand_i32(0xC0FFEEEE, 0x7DCB5691) == 0xBF34B97F
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_umin_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 umin v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umin_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_umin_i64(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_umin_i64(0, 1) == 0
|
|
||||||
; run: %atomic_rmw_umin_i64(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_umin_i64(-1, 1) == 1
|
|
||||||
; run: %atomic_rmw_umin_i64(-1, -3) == -3
|
|
||||||
|
|
||||||
function %atomic_rmw_umin_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 umin v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umin_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_umin_i32(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_umin_i32(0, 1) == 0
|
|
||||||
; run: %atomic_rmw_umin_i32(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_umin_i32(-1, 1) == 1
|
|
||||||
; run: %atomic_rmw_umin_i32(-1, -3) == -3
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_umax_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 umax v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umax_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_umax_i64(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_umax_i64(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_umax_i64(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_umax_i64(-1, 1) == -1
|
|
||||||
; run: %atomic_rmw_umax_i64(-1, -3) == -1
|
|
||||||
|
|
||||||
function %atomic_rmw_umax_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 umax v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_umax_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_umax_i32(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_umax_i32(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_umax_i32(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_umax_i32(-1, 1) == -1
|
|
||||||
; run: %atomic_rmw_umax_i32(-1, -3) == -1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_smin_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 smin v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smin_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_smin_i64(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_smin_i64(0, 1) == 0
|
|
||||||
; run: %atomic_rmw_smin_i64(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_smin_i64(-1, 1) == -1
|
|
||||||
; run: %atomic_rmw_smin_i64(-1, -3) == -3
|
|
||||||
|
|
||||||
function %atomic_rmw_smin_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 smin v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smin_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_smin_i32(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_smin_i32(0, 1) == 0
|
|
||||||
; run: %atomic_rmw_smin_i32(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_smin_i32(-1, -1) == -1
|
|
||||||
; run: %atomic_rmw_smin_i32(-1, -3) == -3
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_smax_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 smax v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smax_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_smax_i64(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_smax_i64(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_smax_i64(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_smax_i64(-1, 1) == 1
|
|
||||||
; run: %atomic_rmw_smax_i64(-1, -3) == -1
|
|
||||||
|
|
||||||
function %atomic_rmw_smax_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 smax v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_smax_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_smax_i32(1, 0) == 1
|
|
||||||
; run: %atomic_rmw_smax_i32(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_smax_i32(1, 1) == 1
|
|
||||||
; run: %atomic_rmw_smax_i32(-1, 1) == 1
|
|
||||||
; run: %atomic_rmw_smax_i32(-1, -3) == -1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %atomic_rmw_xchg_i64(i64, i64) -> i64 {
|
|
||||||
ss0 = explicit_slot 8
|
|
||||||
|
|
||||||
block0(v0: i64, v1: i64):
|
|
||||||
stack_store.i64 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i64 ss0
|
|
||||||
v3 = atomic_rmw.i64 xchg v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i64 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xchg_i64(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_xchg_i64(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_xchg_i64(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_xchg_i64(0, 0xC0FFEEEE_DECAFFFF) == 0xC0FFEEEE_DECAFFFF
|
|
||||||
|
|
||||||
function %atomic_rmw_xchg_i32(i32, i32) -> i32 {
|
|
||||||
ss0 = explicit_slot 4
|
|
||||||
|
|
||||||
block0(v0: i32, v1: i32):
|
|
||||||
stack_store.i32 v0, ss0
|
|
||||||
|
|
||||||
v2 = stack_addr.i32 ss0
|
|
||||||
v3 = atomic_rmw.i32 xchg v2, v1
|
|
||||||
|
|
||||||
v4 = stack_load.i32 ss0
|
|
||||||
return v4
|
|
||||||
}
|
|
||||||
; run: %atomic_rmw_xchg_i32(0, 0) == 0
|
|
||||||
; run: %atomic_rmw_xchg_i32(1, 0) == 0
|
|
||||||
; run: %atomic_rmw_xchg_i32(0, 1) == 1
|
|
||||||
; run: %atomic_rmw_xchg_i32(0, 0xC0FFEEEE) == 0xC0FFEEEE
|
|
||||||
Reference in New Issue
Block a user