[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:
Sam Parker
2022-04-27 21:13:59 +01:00
committed by GitHub
parent 8381179503
commit 12b4374cd5
26 changed files with 1632 additions and 1281 deletions

View File

@@ -209,10 +209,8 @@
;; 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
;; 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
;; followed by a fence which is at least as comprehensive as that of the `Fence`
;; instruction below. This instruction is sequentially consistent. The operand
;; conventions are:
;; in the surrounding code to the extent it can. Load- and store-exclusive instructions,
;; with acquire-release semantics, are used to access memory. The operand conventions are:
;;
;; x25 (rd) address
;; x26 (rd) second operand for `op`
@@ -221,28 +219,10 @@
;; x28 (wr) scratch reg; value afterwards has no meaning
(AtomicRMWLoop
(ty Type) ;; I8, I16, I32 or I64
(op AtomicRmwOp))
;; An atomic read-modify-write operation. These instructions require the
;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have
;; acquire-release semantics.
(AtomicRMW
(op AtomicRMWOp)
(rs Reg)
(rt WritableReg)
(rn Reg)
(ty Type))
;; An atomic compare-and-swap operation. This instruction is sequentially consistent.
(AtomicCAS
(rs WritableReg)
(rt Reg)
(rn Reg)
(ty Type))
(op AtomicRMWLoopOp))
;; Similar to AtomicRMWLoop, a compare-and-swap operation implemented using a load-linked
;; store-conditional loop.
;; This instruction is sequentially consistent.
;; store-conditional loop, with acquire-release semantics.
;; Note that the operand conventions, although very similar to AtomicRMWLoop, are different:
;;
;; x25 (rd) address
@@ -254,6 +234,23 @@
(ty Type) ;; I8, I16, I32 or I64
)
;; An atomic read-modify-write operation. These instructions require the
;; Large System Extension (LSE) ISA support (FEAT_LSE). The instructions have
;; acquire-release semantics.
(AtomicRMW
(op AtomicRMWOp)
(rs Reg)
(rt WritableReg)
(rn Reg)
(ty Type))
;; An atomic compare-and-swap operation. This instruction is sequentially consistent.
(AtomicCAS
(rs WritableReg)
(rt Reg)
(rn Reg)
(ty Type))
;; 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.
;; This instruction is sequentially consistent.
@@ -1261,8 +1258,30 @@
(Smin)
(Umax)
(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 ;;;;;;;;;;;;;;;;;;;;;;;;;;
(decl move_wide_const_from_u64 (MoveWideConst) u64)
@@ -1304,6 +1323,9 @@
(decl integral_ty (Type) Type)
(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`.
(decl imm12_from_value (Imm12) Value)
(extractor
@@ -1345,6 +1367,26 @@
(decl writable_zero_reg () WritableReg)
(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.
(decl movz (MoveWideConst OperandSize) Reg)
(rule (movz imm size)
@@ -2053,3 +2095,30 @@
(decl cmeq0 (Reg VectorSize) Reg)
(rule (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)))

View File

@@ -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.
pub fn from_ty(ty: Type) -> OperandSize {
debug_assert!(!ty.is_vector());

View File

@@ -7,6 +7,7 @@ use crate::ir::constant::ConstantData;
use crate::ir::types::*;
use crate::ir::{LibCall, MemFlags, TrapCode};
use crate::isa::aarch64::inst::*;
use crate::isa::aarch64::lower::is_valid_atomic_transaction_ty;
use crate::machinst::{ty_bits, Reg, RegClass, Writable};
use core::convert::TryFrom;
@@ -505,7 +506,7 @@ fn enc_dmb_ish() -> u32 {
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);
let sz = match ty {
I64 => 0b11,
@@ -514,6 +515,10 @@ fn enc_ldal(ty: Type, op: AtomicRMWOp, rs: Reg, rt: Writable<Reg>, rn: Reg) -> u
I8 => 0b00,
_ => unreachable!(),
};
let bit15 = match op {
AtomicRMWOp::Swp => 0b1,
_ => 0b0,
};
let op = match op {
AtomicRMWOp::Add => 0b000,
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::Umax => 0b110,
AtomicRMWOp::Umin => 0b111,
AtomicRMWOp::Swp => 0b000,
};
0b00_111_000_111_00000_0_000_00_00000_00000
| (sz << 30)
| (machreg_to_gpr(rs) << 16)
| bit15 << 15
| (op << 12)
| (machreg_to_gpr(rn) << 5)
| machreg_to_gpr(rt.to_reg())
@@ -1371,15 +1378,18 @@ impl MachInstEmit for Inst {
sink.put4(enc_ccmp_imm(size, rn, imm, nzcv, cond));
}
&Inst::AtomicRMW { ty, op, rs, rt, rn } => {
assert!(is_valid_atomic_transaction_ty(ty));
let rs = allocs.next(rs);
let rt = allocs.next_writable(rt);
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 } => {
assert!(is_valid_atomic_transaction_ty(ty));
/* Emit this:
again:
ldaxr{,b,h} x/w27, [x25]
// maybe sign extend
op x28, x27, x26 // op is add,sub,and,orr,eor
stlxr{,b,h} w24, x/w28, [x25]
cbnz x24, again
@@ -1414,10 +1424,31 @@ impl MachInstEmit for Inst {
}
sink.put4(enc_ldaxr(ty, x27wr, x25)); // ldaxr x27, [x25]
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 {
AtomicRmwOp::Xchg => {} // do nothing
AtomicRmwOp::Nand => {
AtomicRMWLoopOp::Xchg => {} // do nothing
AtomicRMWLoopOp::Nand => {
// and x28, x27, x26
// mvn x28, x28
@@ -1439,29 +1470,42 @@ impl MachInstEmit for Inst {
}
.emit(&[], sink, emit_info, state);
}
AtomicRmwOp::Umin
| AtomicRmwOp::Umax
| AtomicRmwOp::Smin
| AtomicRmwOp::Smax => {
// cmp x27, x26
AtomicRMWLoopOp::Umin
| AtomicRMWLoopOp::Umax
| AtomicRMWLoopOp::Smin
| AtomicRMWLoopOp::Smax => {
// cmp x27, x26 {?sxt}
// csel.op x28, x27, x26
let cond = match op {
AtomicRmwOp::Umin => Cond::Lo,
AtomicRmwOp::Umax => Cond::Hi,
AtomicRmwOp::Smin => Cond::Lt,
AtomicRmwOp::Smax => Cond::Gt,
AtomicRMWLoopOp::Umin => Cond::Lo,
AtomicRMWLoopOp::Umax => Cond::Hi,
AtomicRMWLoopOp::Smin => Cond::Lt,
AtomicRMWLoopOp::Smax => Cond::Gt,
_ => unreachable!(),
};
Inst::AluRRR {
alu_op: ALUOp::SubS,
size,
rd: writable_zero_reg(),
rn: x27,
rm: x26,
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 {
alu_op: ALUOp::SubS,
size,
rd: writable_zero_reg(),
rn: x27,
rm: x26,
}
.emit(&[], sink, emit_info, state);
}
.emit(&[], sink, emit_info, state);
Inst::CSel {
cond,
@@ -1474,17 +1518,17 @@ impl MachInstEmit for Inst {
_ => {
// add/sub/and/orr/eor x28, x27, x26
let alu_op = match op {
AtomicRmwOp::Add => ALUOp::Add,
AtomicRmwOp::Sub => ALUOp::Sub,
AtomicRmwOp::And => ALUOp::And,
AtomicRmwOp::Or => ALUOp::Orr,
AtomicRmwOp::Xor => ALUOp::Eor,
AtomicRmwOp::Nand
| AtomicRmwOp::Umin
| AtomicRmwOp::Umax
| AtomicRmwOp::Smin
| AtomicRmwOp::Smax
| AtomicRmwOp::Xchg => unreachable!(),
AtomicRMWLoopOp::Add => ALUOp::Add,
AtomicRMWLoopOp::Sub => ALUOp::Sub,
AtomicRMWLoopOp::And => ALUOp::And,
AtomicRMWLoopOp::Orr => ALUOp::Orr,
AtomicRMWLoopOp::Eor => ALUOp::Eor,
AtomicRMWLoopOp::Nand
| AtomicRMWLoopOp::Umin
| AtomicRMWLoopOp::Umax
| AtomicRMWLoopOp::Smin
| AtomicRMWLoopOp::Smax
| AtomicRMWLoopOp::Xchg => unreachable!(),
};
Inst::AluRRR {
@@ -1502,7 +1546,7 @@ impl MachInstEmit for Inst {
if srcloc != SourceLoc::default() {
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]
} else {
sink.put4(enc_stlxr(ty, x24wr, x28, x25)); // stlxr w24, x28, [x25]

View File

@@ -6205,10 +6205,18 @@ fn test_aarch64_binemit() {
"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((
Inst::AtomicRMWLoop {
ty: I16,
op: inst_common::AtomicRmwOp::Xor,
op: AtomicRMWLoopOp::Eor,
},
"3BFF5F487C031A4A3CFF1848B8FFFFB5",
"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((
Inst::AtomicRMWLoop {
ty: I8,
op: inst_common::AtomicRmwOp::Add,
op: AtomicRMWLoopOp::Add,
},
"3BFF5F087C031A0B3CFF1808B8FFFFB5",
"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((
Inst::AtomicRMWLoop {
ty: I32,
op: inst_common::AtomicRmwOp::Or,
op: AtomicRMWLoopOp::Orr,
},
"3BFF5F887C031A2A3CFF1888B8FFFFB5",
"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((
Inst::AtomicRMWLoop {
ty: I64,
op: inst_common::AtomicRmwOp::And,
op: AtomicRMWLoopOp::And,
},
"3BFF5FC87C031A8A3CFF18C8B8FFFFB5",
"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((
Inst::AtomicRMWLoop {
ty: I8,
op: inst_common::AtomicRmwOp::Xchg,
op: AtomicRMWLoopOp::Xchg,
},
"3BFF5F083AFF1808D8FFFFB5",
"1: ldaxrb w27, [x25]; stlxrb w24, w26, [x25]; cbnz w24, 1b",
@@ -6248,15 +6256,23 @@ fn test_aarch64_binemit() {
insns.push((
Inst::AtomicRMWLoop {
ty: I16,
op: inst_common::AtomicRmwOp::Nand,
op: AtomicRMWLoopOp::Nand,
},
"3BFF5F487C031A0AFC033C2A3CFF184898FFFFB5",
"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((
Inst::AtomicRMWLoop {
ty: I32,
op: inst_common::AtomicRmwOp::Smin,
op: AtomicRMWLoopOp::Smin,
},
"3BFF5F887F031A6B7CB39A9A3CFF188898FFFFB5",
"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((
Inst::AtomicRMWLoop {
ty: I64,
op: inst_common::AtomicRmwOp::Smax,
op: AtomicRMWLoopOp::Smax,
},
"3BFF5FC87F031AEB7CC39A9A3CFF18C898FFFFB5",
"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((
Inst::AtomicRMWLoop {
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",
"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((
Inst::AtomicRMWLoop {
ty: I16,
op: inst_common::AtomicRmwOp::Umax,
op: AtomicRMWLoopOp::Umax,
},
"3BFF5F487F031A6B7C839A9A3CFF184898FFFFB5",
"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",
"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((
Inst::AtomicCAS {

View File

@@ -39,9 +39,9 @@ mod emit_tests;
// Instructions (top level): definition
pub use crate::isa::aarch64::lower::isle::generated_code::{
ALUOp, ALUOp3, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode, FpuToIntOp,
IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2, VecPairOp,
VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
ALUOp, ALUOp3, AtomicRMWLoopOp, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode,
FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2,
VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
};
/// A floating-point unit (FPU) operation with two args, a register and an immediate.
@@ -676,12 +676,14 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
&Inst::CCmpImm { rn, .. } => {
collector.reg_use(rn);
}
&Inst::AtomicRMWLoop { .. } => {
&Inst::AtomicRMWLoop { op, .. } => {
collector.reg_use(xreg(25));
collector.reg_use(xreg(26));
collector.reg_def(writable_xreg(24));
collector.reg_def(writable_xreg(27));
collector.reg_def(writable_xreg(28));
if op != AtomicRMWLoopOp::Xchg {
collector.reg_def(writable_xreg(28));
}
}
&Inst::AtomicRMW { rs, rt, rn, .. } => {
collector.reg_use(rs);
@@ -1538,6 +1540,7 @@ impl Inst {
AtomicRMWOp::Umax => "ldumaxal",
AtomicRMWOp::Smin => "ldsminal",
AtomicRMWOp::Umin => "lduminal",
AtomicRMWOp::Swp => "swpal",
};
let size = OperandSize::from_ty(ty);
@@ -1569,28 +1572,39 @@ impl Inst {
loop_str.push_str(&format!("ldaxr{} {}, [{}]; ", ty_suffix, r_tmp, r_addr));
let op_str = match op {
inst_common::AtomicRmwOp::Add => "add",
inst_common::AtomicRmwOp::Sub => "sub",
inst_common::AtomicRmwOp::Xor => "eor",
inst_common::AtomicRmwOp::Or => "orr",
inst_common::AtomicRmwOp::And => "and",
AtomicRMWLoopOp::Add => "add",
AtomicRMWLoopOp::Sub => "sub",
AtomicRMWLoopOp::Eor => "eor",
AtomicRMWLoopOp::Orr => "orr",
AtomicRMWLoopOp::And => "and",
_ => "",
};
if op_str.is_empty() {
match op {
inst_common::AtomicRmwOp::Xchg => r_dst = r_arg2,
inst_common::AtomicRmwOp::Nand => {
AtomicRMWLoopOp::Xchg => r_dst = r_arg2,
AtomicRMWLoopOp::Nand => {
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!("cmp {}, {}; ", r_tmp, r_arg2));
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));
}
let cond = match op {
inst_common::AtomicRmwOp::Smin => "lt",
inst_common::AtomicRmwOp::Smax => "gt",
inst_common::AtomicRmwOp::Umin => "lo",
inst_common::AtomicRmwOp::Umax => "hi",
AtomicRMWLoopOp::Smin => "lt",
AtomicRMWLoopOp::Smax => "gt",
AtomicRMWLoopOp::Umin => "lo",
AtomicRMWLoopOp::Umax => "hi",
_ => unreachable!(),
};
loop_str.push_str(&format!(

View File

@@ -1196,3 +1196,77 @@
(let ((rn Reg y)
(vec_size VectorSize (vector_size ty)))
(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))

View File

@@ -5,8 +5,8 @@ pub mod generated_code;
// Types that the generated ISLE code uses via `use super::*`.
use super::{
writable_zero_reg, zero_reg, AMode, ASIMDFPModImm, ASIMDMovModImm, AtomicRmwOp, BranchTarget,
CallIndInfo, CallInfo, Cond, CondBrKind, ExtendOp, FPUOpRI, FloatCC, Imm12, ImmLogic, ImmShift,
writable_zero_reg, zero_reg, AMode, ASIMDFPModImm, ASIMDMovModImm, BranchTarget, CallIndInfo,
CallInfo, Cond, CondBrKind, ExtendOp, FPUOpRI, FloatCC, Imm12, ImmLogic, ImmShift,
Inst as MInst, IntCC, JTSequenceInfo, MachLabel, MoveWideConst, MoveWideOp, NarrowValueMode,
Opcode, OperandSize, PairAMode, Reg, ScalarSize, ShiftOpAndAmt, UImm5, VecMisc2, VectorSize,
NZCV,
@@ -17,10 +17,11 @@ use crate::settings::Flags;
use crate::{
binemit::CodeOffset,
ir::{
immediates::*, types::*, ExternalName, Inst, InstructionData, MemFlags, TrapCode, Value,
ValueList,
immediates::*, types::*, AtomicRmwOp, ExternalName, Inst, InstructionData, MemFlags,
TrapCode, Value, ValueList,
},
isa::aarch64::inst::args::{ShiftOp, ShiftOpShiftImm},
isa::aarch64::lower::{is_valid_atomic_transaction_ty, writable_xreg, xreg},
isa::unwind::UnwindInst,
machinst::{ty_bits, InsnOutput, LowerCtx},
};
@@ -66,6 +67,14 @@ where
{
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> {
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
/// register.
///
@@ -194,6 +211,14 @@ where
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> {
let (val, extend) =
super::get_as_extended_value(self.lower_ctx, val, NarrowValueMode::None)?;

View File

@@ -1,4 +1,4 @@
src/clif.isle 443b34b797fc8ace
src/prelude.isle d8a93eb727abd7f4
src/isa/aarch64/inst.isle 77984cc33a05be7
src/isa/aarch64/lower.isle 71c7e603b0e4bdef
src/prelude.isle a7915a6b88310eb5
src/isa/aarch64/inst.isle a2c0ae729bfa24a8
src/isa/aarch64/lower.isle 15641ca7f0ac061a

File diff suppressed because it is too large Load Diff

View File

@@ -237,48 +237,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(inst);
}
Opcode::AtomicRmw => {
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::AtomicRmw => implemented_in_isle(ctx),
Opcode::AtomicCas => {
let r_dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();

View File

@@ -1,4 +1,4 @@
src/clif.isle 443b34b797fc8ace
src/prelude.isle d8a93eb727abd7f4
src/prelude.isle a7915a6b88310eb5
src/isa/s390x/inst.isle 8218bd9e8556446b
src/isa/s390x/lower.isle 6a8de81f8dc4e568

View File

@@ -35,6 +35,7 @@ pub trait Context {
fn invalid_reg(&mut self) -> Reg;
fn put_in_reg(&mut self, arg0: Value) -> Reg;
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 u8_as_u64(&mut self, arg0: u8) -> 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<()>;
}
/// Internal type SideEffectNoResult: defined at src/prelude.isle line 407.
/// Internal type SideEffectNoResult: defined at src/prelude.isle line 412.
#[derive(Clone, Debug)]
pub enum SideEffectNoResult {
Inst { inst: 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)]
pub enum ProducesFlags {
ProducesFlagsSideEffect { inst: MInst },
@@ -170,7 +171,7 @@ pub enum ProducesFlags {
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)]
pub enum ConsumesFlags {
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.
pub fn constructor_lo_reg<C: Context>(ctx: &mut C, arg0: Value) -> Option<Reg> {
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 expr1_0: usize = 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 {
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 expr1_0 = C::output_none(ctx);
return Some(expr1_0);
@@ -969,7 +970,7 @@ pub fn constructor_side_effect<C: Context>(
inst1: ref pattern1_0,
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 expr1_0 = C::emit(ctx, pattern1_1);
let expr2_0 = C::output_none(ctx);
@@ -996,7 +997,7 @@ pub fn constructor_side_effect_concat<C: Context>(
inst: ref pattern3_0,
} = pattern2_0
{
// Rule at src/prelude.isle line 424.
// Rule at src/prelude.isle line 429.
let expr0_0 = SideEffectNoResult::Inst2 {
inst1: pattern1_0.clone(),
inst2: pattern3_0.clone(),
@@ -1018,7 +1019,7 @@ pub fn constructor_produces_flags_get_reg<C: Context>(
result: pattern1_1,
} = pattern0_0
{
// Rule at src/prelude.isle line 461.
// Rule at src/prelude.isle line 466.
return Some(pattern1_1);
}
return None;
@@ -1035,7 +1036,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
inst: ref pattern1_0,
result: pattern1_1,
} => {
// Rule at src/prelude.isle line 466.
// Rule at src/prelude.isle line 471.
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
inst: pattern1_0.clone(),
};
@@ -1045,7 +1046,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
inst: ref pattern1_0,
result: pattern1_1,
} => {
// Rule at src/prelude.isle line 468.
// Rule at src/prelude.isle line 473.
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
inst: pattern1_0.clone(),
};
@@ -1074,7 +1075,7 @@ pub fn constructor_consumes_flags_concat<C: Context>(
result: pattern3_1,
} = 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 expr1_0 = ConsumesFlags::ConsumesFlagsTwiceReturnsValueRegs {
inst1: pattern1_0.clone(),
@@ -1104,7 +1105,7 @@ pub fn constructor_with_flags<C: Context>(
inst: ref pattern3_0,
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 expr1_0 = C::emit(ctx, pattern3_0);
let expr2_0 = C::value_reg(ctx, pattern3_1);
@@ -1115,7 +1116,7 @@ pub fn constructor_with_flags<C: Context>(
inst2: ref pattern3_1,
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 expr1_0 = C::emit(ctx, pattern3_0);
let expr2_0 = C::emit(ctx, pattern3_1);
@@ -1128,7 +1129,7 @@ pub fn constructor_with_flags<C: Context>(
inst4: ref pattern3_3,
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 expr1_0 = C::emit(ctx, pattern3_0);
let expr2_0 = C::emit(ctx, pattern3_1);
@@ -1149,7 +1150,7 @@ pub fn constructor_with_flags<C: Context>(
result: pattern3_1,
} = 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 expr1_0 = C::emit(ctx, pattern3_0);
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> {
let pattern0_0 = arg0;
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 expr1_0: usize = 0;
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);

View File

@@ -1,4 +1,4 @@
src/clif.isle 443b34b797fc8ace
src/prelude.isle d8a93eb727abd7f4
src/prelude.isle a7915a6b88310eb5
src/isa/x64/inst.isle 6dcba190988a695
src/isa/x64/lower.isle b95161bdf07b9365

View File

@@ -35,6 +35,7 @@ pub trait Context {
fn invalid_reg(&mut self) -> Reg;
fn put_in_reg(&mut self, arg0: Value) -> Reg;
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 u8_as_u64(&mut self, arg0: u8) -> u64;
fn u16_as_u64(&mut self, arg0: u16) -> u64;
@@ -163,14 +164,14 @@ pub trait Context {
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)]
pub enum SideEffectNoResult {
Inst { inst: 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)]
pub enum ProducesFlags {
ProducesFlagsSideEffect { inst: MInst },
@@ -178,7 +179,7 @@ pub enum ProducesFlags {
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)]
pub enum ConsumesFlags {
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.
pub fn constructor_lo_reg<C: Context>(ctx: &mut C, arg0: Value) -> Option<Reg> {
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 expr1_0: usize = 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 {
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 expr1_0 = C::output_none(ctx);
return Some(expr1_0);
@@ -588,7 +589,7 @@ pub fn constructor_side_effect<C: Context>(
inst1: ref pattern1_0,
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 expr1_0 = C::emit(ctx, pattern1_1);
let expr2_0 = C::output_none(ctx);
@@ -615,7 +616,7 @@ pub fn constructor_side_effect_concat<C: Context>(
inst: ref pattern3_0,
} = pattern2_0
{
// Rule at src/prelude.isle line 424.
// Rule at src/prelude.isle line 429.
let expr0_0 = SideEffectNoResult::Inst2 {
inst1: pattern1_0.clone(),
inst2: pattern3_0.clone(),
@@ -637,7 +638,7 @@ pub fn constructor_produces_flags_get_reg<C: Context>(
result: pattern1_1,
} = pattern0_0
{
// Rule at src/prelude.isle line 461.
// Rule at src/prelude.isle line 466.
return Some(pattern1_1);
}
return None;
@@ -654,7 +655,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
inst: ref pattern1_0,
result: pattern1_1,
} => {
// Rule at src/prelude.isle line 466.
// Rule at src/prelude.isle line 471.
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
inst: pattern1_0.clone(),
};
@@ -664,7 +665,7 @@ pub fn constructor_produces_flags_ignore<C: Context>(
inst: ref pattern1_0,
result: pattern1_1,
} => {
// Rule at src/prelude.isle line 468.
// Rule at src/prelude.isle line 473.
let expr0_0 = ProducesFlags::ProducesFlagsSideEffect {
inst: pattern1_0.clone(),
};
@@ -693,7 +694,7 @@ pub fn constructor_consumes_flags_concat<C: Context>(
result: pattern3_1,
} = 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 expr1_0 = ConsumesFlags::ConsumesFlagsTwiceReturnsValueRegs {
inst1: pattern1_0.clone(),
@@ -723,7 +724,7 @@ pub fn constructor_with_flags<C: Context>(
inst: ref pattern3_0,
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 expr1_0 = C::emit(ctx, pattern3_0);
let expr2_0 = C::value_reg(ctx, pattern3_1);
@@ -734,7 +735,7 @@ pub fn constructor_with_flags<C: Context>(
inst2: ref pattern3_1,
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 expr1_0 = C::emit(ctx, pattern3_0);
let expr2_0 = C::emit(ctx, pattern3_1);
@@ -747,7 +748,7 @@ pub fn constructor_with_flags<C: Context>(
inst4: ref pattern3_3,
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 expr1_0 = C::emit(ctx, pattern3_0);
let expr2_0 = C::emit(ctx, pattern3_1);
@@ -768,7 +769,7 @@ pub fn constructor_with_flags<C: Context>(
result: pattern3_1,
} = 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 expr1_0 = C::emit(ctx, pattern3_0);
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> {
let pattern0_0 = arg0;
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 expr1_0: usize = 0;
let expr2_0 = C::value_regs_get(ctx, expr0_0, expr1_0);

View File

@@ -120,6 +120,11 @@ macro_rules! isle_prelude_methods {
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]
fn value_regs_get(&mut self, regs: ValueRegs, i: usize) -> Reg {
regs.regs()[i]

View File

@@ -129,6 +129,11 @@
(decl put_in_regs (Value) ValueRegs)
(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`.
(decl value_regs_get (ValueRegs usize) Reg)
(extern constructor value_regs_get value_regs_get)

View File

@@ -41,6 +41,50 @@ block0(v0: i64, v1: i8):
; ldaddalb w1, w4, [x0]
; 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) {
block0(v0: i64, v1: i64):
v2 = atomic_rmw.i64 and v0, v1
@@ -48,7 +92,8 @@ block0(v0: i64, v1: i64):
}
; block0:
; ldclral x1, x4, [x0]
; eon x4, x1, xzr
; ldclral x4, x6, [x0]
; ret
function %atomic_rmw_and_i32(i64, i32) {
@@ -58,7 +103,8 @@ block0(v0: i64, v1: i32):
}
; block0:
; ldclral w1, w4, [x0]
; eon w4, w1, wzr
; ldclral w4, w6, [x0]
; ret
function %atomic_rmw_and_i16(i64, i16) {
@@ -68,7 +114,8 @@ block0(v0: i64, v1: i16):
}
; block0:
; ldclralh w1, w4, [x0]
; eon w4, w1, wzr
; ldclralh w4, w6, [x0]
; ret
function %atomic_rmw_and_i8(i64, i8) {
@@ -78,7 +125,8 @@ block0(v0: i64, v1: i8):
}
; block0:
; ldclralb w1, w4, [x0]
; eon w4, w1, wzr
; ldclralb w4, w6, [x0]
; ret
function %atomic_rmw_nand_i64(i64, i64) {

View File

@@ -89,6 +89,94 @@ block0(v0: i64, v1: i8):
; ldp fp, lr, [sp], #16
; 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) {
block0(v0: i64, v1: i64):
v2 = atomic_rmw.i64 and v0, v1
@@ -500,7 +588,7 @@ block0(v0: i64, v1: i16):
; mov x25, x0
; mov x4, x1
; 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 x26, x27, [sp], #16
; ldr x28, [sp], #16
@@ -522,7 +610,7 @@ block0(v0: i64, v1: i8):
; mov x25, x0
; mov x4, x1
; 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 x26, x27, [sp], #16
; ldr x28, [sp], #16
@@ -676,7 +764,7 @@ block0(v0: i64, v1: i16):
; mov x25, x0
; mov x4, x1
; 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 x26, x27, [sp], #16
; ldr x28, [sp], #16
@@ -698,7 +786,7 @@ block0(v0: i64, v1: i8):
; mov x25, x0
; mov x4, x1
; 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 x26, x27, [sp], #16
; ldr x28, [sp], #16

View File

@@ -25,7 +25,7 @@ function %atomic_cas_i32(i32, i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32, v2: i32):
v3 = stack_addr.i32 ss0
v3 = stack_addr.i64 ss0
store.i32 little v0, v3
v4 = atomic_cas.i32 little v3, v1, v2

View File

@@ -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

View File

@@ -1,27 +1,12 @@
test run
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
; 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 {
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, 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 {
ss0 = explicit_slot 4

View File

@@ -30,7 +30,7 @@ function %atomic_cas_i32(i32, i32, i32) -> i32 {
block0(v0: i32, v1: i32, v2: i32):
stack_store.i32 v0, ss0
v3 = stack_addr.i32 ss0
v3 = stack_addr.i64 ss0
v4 = atomic_cas.i32 v3, v1, v2
v5 = stack_load.i32 ss0

View File

@@ -1,5 +1,8 @@
test run
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
; test if they perform their operation correctly
@@ -26,7 +29,7 @@ function %atomic_rmw_add_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little add v2, v1
@@ -64,7 +67,7 @@ function %atomic_rmw_sub_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little sub v2, v1
@@ -102,7 +105,7 @@ function %atomic_rmw_and_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little and v2, v1
@@ -141,7 +144,7 @@ function %atomic_rmw_or_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little or v2, v1
@@ -180,7 +183,7 @@ function %atomic_rmw_xor_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little xor v2, v1
@@ -218,7 +221,7 @@ function %atomic_rmw_nand_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little nand v2, v1
@@ -257,7 +260,7 @@ function %atomic_rmw_umin_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little umin v2, v1
@@ -297,7 +300,7 @@ function %atomic_rmw_umax_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little umax v2, v1
@@ -337,7 +340,7 @@ function %atomic_rmw_smin_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little smin v2, v1
@@ -377,7 +380,7 @@ function %atomic_rmw_smax_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little smax v2, v1
@@ -415,7 +418,7 @@ function %atomic_rmw_xchg_i32(i32, i32) -> i32 {
ss0 = explicit_slot 4
block0(v0: i32, v1: i32):
v2 = stack_addr.i32 ss0
v2 = stack_addr.i64 ss0
store.i32 little v0, v2
v3 = atomic_rmw.i32 little xchg v2, v1

View File

@@ -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

View File

@@ -1,27 +1,12 @@
test run
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
; 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 {
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, 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 {
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, 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 {
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, 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 {
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, 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 {
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, 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 {
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
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 {
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, 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 {
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, 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 {
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, 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 {
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
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 {
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, 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 {
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
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 {
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, 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 {
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
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 {
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, 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 {
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
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 {
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, 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 {
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
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 {
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, 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 {
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
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 {
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, 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 {
ss0 = explicit_slot 4

View File

@@ -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