Skip to content

atomic_load intrinsic: use const generic parameter for ordering #141507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,11 +870,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
// FIXME use a compiler fence once Cranelift supports it
fx.bcx.ins().fence();
}
_ if intrinsic.as_str().starts_with("atomic_load") => {
sym::atomic_load => {
intrinsic_args!(fx, args => (ptr); intrinsic);
let ptr = ptr.load_scalar(fx);

let ty = generic_args.type_at(0);
let _ord = generic_args.const_at(1).to_value(); // FIXME: forward this to cranelift once they support that
match ty.kind() {
ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
// FIXME implement 128bit atomics
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout, WrappingRange};
use rustc_apfloat::{Float, Round, Status, ieee};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::common::{
AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
};
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
Expand All @@ -26,7 +26,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_target::callconv::FnAbi;
Expand Down Expand Up @@ -75,7 +75,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {

let load_ordering = match order {
// TODO(antoyo): does this make sense?
AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire,
AtomicOrdering::AcqRel | AtomicOrdering::Release => AtomicOrdering::Acquire,
_ => order,
};
let previous_value =
Expand Down Expand Up @@ -2474,8 +2474,8 @@ impl ToGccOrdering for AtomicOrdering {
AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
AtomicOrdering::Acquire => __ATOMIC_ACQUIRE,
AtomicOrdering::Release => __ATOMIC_RELEASE,
AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL,
AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST,
AtomicOrdering::AcqRel => __ATOMIC_ACQ_REL,
AtomicOrdering::SeqCst => __ATOMIC_SEQ_CST,
};
ordering as i32
}
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
&mut self,
ty: &'ll Type,
ptr: &'ll Value,
order: rustc_codegen_ssa::common::AtomicOrdering,
order: rustc_middle::ty::AtomicOrdering,
size: Size,
) -> &'ll Value {
unsafe {
Expand Down Expand Up @@ -851,7 +851,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
&mut self,
val: &'ll Value,
ptr: &'ll Value,
order: rustc_codegen_ssa::common::AtomicOrdering,
order: rustc_middle::ty::AtomicOrdering,
size: Size,
) {
debug!("Store {:?} -> {:?}", val, ptr);
Expand Down Expand Up @@ -1307,8 +1307,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
dst: &'ll Value,
cmp: &'ll Value,
src: &'ll Value,
order: rustc_codegen_ssa::common::AtomicOrdering,
failure_order: rustc_codegen_ssa::common::AtomicOrdering,
order: rustc_middle::ty::AtomicOrdering,
failure_order: rustc_middle::ty::AtomicOrdering,
weak: bool,
) -> (&'ll Value, &'ll Value) {
let weak = if weak { llvm::True } else { llvm::False };
Expand All @@ -1334,7 +1334,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
op: rustc_codegen_ssa::common::AtomicRmwBinOp,
dst: &'ll Value,
mut src: &'ll Value,
order: rustc_codegen_ssa::common::AtomicOrdering,
order: rustc_middle::ty::AtomicOrdering,
) -> &'ll Value {
// The only RMW operation that LLVM supports on pointers is compare-exchange.
let requires_cast_to_int = self.val_ty(src) == self.type_ptr()
Expand All @@ -1360,7 +1360,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {

fn atomic_fence(
&mut self,
order: rustc_codegen_ssa::common::AtomicOrdering,
order: rustc_middle::ty::AtomicOrdering,
scope: SynchronizationScope,
) {
let single_threaded = match scope {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,14 +426,14 @@ pub(crate) enum AtomicOrdering {
}

impl AtomicOrdering {
pub(crate) fn from_generic(ao: rustc_codegen_ssa::common::AtomicOrdering) -> Self {
use rustc_codegen_ssa::common::AtomicOrdering as Common;
pub(crate) fn from_generic(ao: rustc_middle::ty::AtomicOrdering) -> Self {
use rustc_middle::ty::AtomicOrdering as Common;
match ao {
Common::Relaxed => Self::Monotonic,
Common::Acquire => Self::Acquire,
Common::Release => Self::Release,
Common::AcquireRelease => Self::AcquireRelease,
Common::SequentiallyConsistent => Self::SequentiallyConsistent,
Common::AcqRel => Self::AcquireRelease,
Common::SeqCst => Self::SequentiallyConsistent,
}
}
}
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_codegen_ssa/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,6 @@ pub enum AtomicRmwBinOp {
AtomicUMin,
}

#[derive(Copy, Clone, Debug)]
pub enum AtomicOrdering {
Relaxed,
Acquire,
Release,
AcquireRelease,
SequentiallyConsistent,
}

#[derive(Copy, Clone, Debug)]
pub enum SynchronizationScope {
SingleThread,
Expand Down
91 changes: 54 additions & 37 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

let llret_ty = bx.backend_type(bx.layout_of(ret_ty));

let ret_llval = |bx: &mut Bx, llval| {
if result.layout.ty.is_bool() {
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
.val
.store(bx, result);
} else if !result.layout.ty.is_unit() {
bx.store_to_place(llval, result.val);
}
Ok(())
};

let llval = match name {
sym::abort => {
bx.abort();
Expand Down Expand Up @@ -334,9 +345,48 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// This requires that atomic intrinsics follow a specific naming pattern:
// "atomic_<operation>[_<ordering>]"
name if let Some(atomic) = name_str.strip_prefix("atomic_") => {
use crate::common::AtomicOrdering::*;
use rustc_middle::ty::AtomicOrdering::*;

use crate::common::{AtomicRmwBinOp, SynchronizationScope};

let invalid_monomorphization = |ty| {
bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
span,
name,
ty,
});
};

let parse_const_generic_ordering = |ord: ty::Value<'tcx>| {
let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf();
discr.to_atomic_ordering()
};

// Some intrinsics have the ordering already converted to a const generic parameter, we handle those first.
match name {
sym::atomic_load => {
let ty = fn_args.type_at(0);
let ordering = fn_args.const_at(1).to_value();
if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
invalid_monomorphization(ty);
return Ok(());
}
let layout = bx.layout_of(ty);
let source = args[0].immediate();
let llval = bx.atomic_load(
bx.backend_type(layout),
source,
parse_const_generic_ordering(ordering),
layout.size,
);

return ret_llval(bx, llval);
}

// The rest falls back to below.
_ => {}
}

let Some((instruction, ordering)) = atomic.split_once('_') else {
bx.sess().dcx().emit_fatal(errors::MissingMemoryOrdering);
};
Expand All @@ -345,19 +395,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
"relaxed" => Relaxed,
"acquire" => Acquire,
"release" => Release,
"acqrel" => AcquireRelease,
"seqcst" => SequentiallyConsistent,
"acqrel" => AcqRel,
"seqcst" => SeqCst,
_ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOrdering),
};

let invalid_monomorphization = |ty| {
bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
span,
name,
ty,
});
};

match instruction {
"cxchg" | "cxchgweak" => {
let Some((success, failure)) = ordering.split_once('_') else {
Expand Down Expand Up @@ -390,24 +432,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return Ok(());
}

"load" => {
let ty = fn_args.type_at(0);
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
let layout = bx.layout_of(ty);
let size = layout.size;
let source = args[0].immediate();
bx.atomic_load(
bx.backend_type(layout),
source,
parse_ordering(bx, ordering),
size,
)
} else {
invalid_monomorphization(ty);
return Ok(());
}
}

"store" => {
let ty = fn_args.type_at(0);
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
Expand Down Expand Up @@ -538,14 +562,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
};

if result.layout.ty.is_bool() {
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
.val
.store(bx, result);
} else if !result.layout.ty.is_unit() {
bx.store_to_place(llval, result.val);
}
Ok(())
ret_llval(bx, llval)
}
}

Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::ops::Deref;
use rustc_abi::{Align, Scalar, Size, WrappingRange};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
use rustc_middle::ty::{Instance, Ty};
use rustc_middle::ty::{AtomicOrdering, Instance, Ty};
use rustc_session::config::OptLevel;
use rustc_span::Span;
use rustc_target::callconv::FnAbi;
Expand All @@ -19,9 +19,7 @@ use super::misc::MiscCodegenMethods;
use super::type_::{ArgAbiBuilderMethods, BaseTypeCodegenMethods, LayoutTypeCodegenMethods};
use super::{CodegenMethods, StaticBuilderMethods};
use crate::MemFlags;
use crate::common::{
AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
};
use crate::common::{AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
use crate::mir::operand::{OperandRef, OperandValue};
use crate::mir::place::{PlaceRef, PlaceValue};

Expand Down
13 changes: 7 additions & 6 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,24 +204,25 @@ pub(crate) fn check_intrinsic_type(

// Each atomic op has variants with different suffixes (`_seq_cst`, `_acquire`, etc.). Use
// string ops to strip the suffixes, because the variants all get the same treatment here.
let (n_tps, inputs, output) = match split[1] {
let (n_tps, n_cts, inputs, output) = match split[1] {
"cxchg" | "cxchgweak" => (
1,
0,
vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)],
Ty::new_tup(tcx, &[param(0), tcx.types.bool]),
),
"load" => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
"store" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit),
"load" => (1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
"store" => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit),

"xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax"
| "umin" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)),
"fence" | "singlethreadfence" => (0, Vec::new(), tcx.types.unit),
| "umin" => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)),
"fence" | "singlethreadfence" => (0, 0, Vec::new(), tcx.types.unit),
op => {
tcx.dcx().emit_err(UnrecognizedAtomicOperation { span, op });
return;
}
};
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
(n_tps, 0, n_cts, inputs, output, hir::Safety::Unsafe)
} else if intrinsic_name == sym::contract_check_ensures {
// contract_check_ensures::<Ret, C>(Ret, C) -> Ret
// where C: for<'a> Fn(&'a Ret) -> bool,
Expand Down
34 changes: 33 additions & 1 deletion compiler/rustc_middle/src/ty/consts/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ impl ConstInt {
}
}

/// An enum to represent the compiler-side view of `intrinsics::AtomicOrdering`.
/// This lives here because there's a method in this file that needs it and it is entirely unclear
/// where else to put this...
#[derive(Debug, Copy, Clone)]
pub enum AtomicOrdering {
// These values must match `intrinsics::AtomicOrdering`!
Relaxed = 0,
Release = 1,
Acquire = 2,
AcqRel = 3,
SeqCst = 4,
}

impl std::fmt::Debug for ConstInt {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { int, signed, is_ptr_sized_integral } = *self;
Expand Down Expand Up @@ -318,6 +331,25 @@ impl ScalarInt {
self.to_uint(tcx.data_layout.pointer_size).try_into().unwrap()
}

#[inline]
pub fn to_atomic_ordering(self) -> AtomicOrdering {
use AtomicOrdering::*;
let val = self.to_u32();
if val == Relaxed as u32 {
Relaxed
} else if val == Release as u32 {
Release
} else if val == Acquire as u32 {
Acquire
} else if val == AcqRel as u32 {
AcqRel
} else if val == SeqCst as u32 {
SeqCst
} else {
panic!("not a valid atomic ordering")
}
}

/// Converts the `ScalarInt` to `bool`.
/// Panics if the `size` of the `ScalarInt` is not equal to 1 byte.
/// Errors if it is not a valid `bool`.
Expand Down Expand Up @@ -488,7 +520,7 @@ from_scalar_int_for_x_signed!(i8, i16, i32, i64, i128);
impl From<std::cmp::Ordering> for ScalarInt {
#[inline]
fn from(c: std::cmp::Ordering) -> Self {
// Here we rely on `Ordering` having the same values in host and target!
// Here we rely on `cmp::Ordering` having the same values in host and target!
ScalarInt::from(c as i8)
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ pub use self::closure::{
place_to_string_for_capture,
};
pub use self::consts::{
AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst,
ValTree, ValTreeKind, Value,
AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt,
UnevaluatedConst, ValTree, ValTreeKind, Value,
};
pub use self::context::{
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ symbols! {
async_iterator_poll_next,
async_trait_bounds,
atomic,
atomic_load,
atomic_mod,
atomics,
att_syntax,
Expand Down
Loading
Loading