cranelift: Add atomic_rmw to interpreter (#5817) (#5856)

As per the linked issue, atomic_rmw was implemented without specific regard for thread safety.
Additionally, the relevant filetest (atomic-rmw-little.clif) was enabled and altered to fix an
inccorrect call to test function `%atomic_rmw_and_i64` after setting up test function
`%atomic_rmw_and_i32`.
This commit is contained in:
Jan-Justin van Tonder
2023-02-23 11:24:56 +01:00
committed by GitHub
parent f6c6bc2155
commit 0521155896
2 changed files with 43 additions and 8 deletions

View File

@@ -1,3 +1,4 @@
test interpret
test run
target s390x
target s390x has_mie2
@@ -116,11 +117,11 @@ block0(v0: i32, v1: i32):
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
; run: %atomic_rmw_and_i32(0, 0) == 0
; run: %atomic_rmw_and_i32(1, 0) == 0
; run: %atomic_rmw_and_i32(0, 1) == 0
; run: %atomic_rmw_and_i32(1, 1) == 1
; run: %atomic_rmw_and_i32(0xF1FFFEFE, 0xCEFFEFEF) == 0xC0FFEEEE

View File

@@ -7,8 +7,8 @@ use crate::value::{Value, ValueConversionKind, ValueError, ValueResult};
use cranelift_codegen::data_value::DataValue;
use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
use cranelift_codegen::ir::{
types, AbiParam, Block, BlockCall, ExternalName, FuncRef, Function, InstructionData, Opcode,
TrapCode, Type, Value as ValueRef,
types, AbiParam, AtomicRmwOp, Block, BlockCall, ExternalName, FuncRef, Function,
InstructionData, Opcode, TrapCode, Type, Value as ValueRef,
};
use log::trace;
use smallvec::{smallvec, SmallVec};
@@ -1187,7 +1187,41 @@ where
Value::convert(arg(0)?, ValueConversionKind::ExtractUpper(types::I64))?,
]),
Opcode::Iconcat => assign(Value::concat(arg(0)?, arg(1)?)?),
Opcode::AtomicRmw => unimplemented!("AtomicRmw"),
Opcode::AtomicRmw => {
let op = inst.atomic_rmw_op().unwrap();
let val = arg(1)?;
let addr = arg(0)?.into_int()? as u64;
let loaded = Address::try_from(addr).and_then(|addr| state.checked_load(addr, ctrl_ty));
let prev_val = match loaded {
Ok(v) => v,
Err(e) => return Ok(ControlFlow::Trap(CraneliftTrap::User(memerror_to_trap(e)))),
};
let prev_val_to_assign = prev_val.clone();
let replace = match op {
AtomicRmwOp::Xchg => Ok(val),
AtomicRmwOp::Add => Value::add(prev_val, val),
AtomicRmwOp::Sub => Value::sub(prev_val, val),
AtomicRmwOp::And => Value::and(prev_val, val),
AtomicRmwOp::Or => Value::or(prev_val, val),
AtomicRmwOp::Xor => Value::xor(prev_val, val),
AtomicRmwOp::Nand => Value::and(prev_val, val).and_then(V::not),
AtomicRmwOp::Smax => Value::max(prev_val, val),
AtomicRmwOp::Smin => Value::min(prev_val, val),
AtomicRmwOp::Umax => Value::max(
Value::convert(val, ValueConversionKind::ToUnsigned)?,
Value::convert(prev_val, ValueConversionKind::ToUnsigned)?,
)
.and_then(|v| Value::convert(v, ValueConversionKind::ToSigned)),
AtomicRmwOp::Umin => Value::min(
Value::convert(val, ValueConversionKind::ToUnsigned)?,
Value::convert(prev_val, ValueConversionKind::ToUnsigned)?,
)
.and_then(|v| Value::convert(v, ValueConversionKind::ToSigned)),
}?;
let stored =
Address::try_from(addr).and_then(|addr| state.checked_store(addr, replace));
assign_or_memtrap(stored.map(|_| prev_val_to_assign))
}
Opcode::AtomicCas => unimplemented!("AtomicCas"),
Opcode::AtomicLoad => {
let load_ty = inst_context.controlling_type().unwrap();