Skip to content

Commit 1f76d21

Browse files
committed
Auto merge of rust-lang#139992 - matthiaskrgr:rollup-ak3uibu, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - rust-lang#139351 (Autodiff batching2) - rust-lang#139483 (f*::NAN: guarantee that this is a quiet NaN) - rust-lang#139498 (Ignore zero-sized types in wasm future-compat warning) - rust-lang#139967 (Introduce and use specialized `//@ ignore-auxiliary` for test support files instead of using `//@ ignore-test`) - rust-lang#139969 (update libc) - rust-lang#139971 (Make C string merging test work on MIPS) - rust-lang#139974 (Change `InterpCx::instantiate*` function visibility to pub) - rust-lang#139977 (Fix drop handling in `hint::select_unpredictable`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents a15cce2 + dc2d273 commit 1f76d21

File tree

69 files changed

+387
-141
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+387
-141
lines changed

Diff for: Cargo.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -2022,9 +2022,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7"
20222022

20232023
[[package]]
20242024
name = "libc"
2025-
version = "0.2.171"
2025+
version = "0.2.172"
20262026
source = "registry+https://github.com/rust-lang/crates.io-index"
2027-
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
2027+
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
20282028

20292029
[[package]]
20302030
name = "libdbus-sys"

Diff for: compiler/rustc_ast/src/expand/autodiff_attrs.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,32 @@ pub enum DiffActivity {
5050
/// with it.
5151
Dual,
5252
/// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
53+
/// with it. It expects the shadow argument to be `width` times larger than the original
54+
/// input/output.
55+
Dualv,
56+
/// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
5357
/// with it. Drop the code which updates the original input/output for maximum performance.
5458
DualOnly,
59+
/// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
60+
/// with it. Drop the code which updates the original input/output for maximum performance.
61+
/// It expects the shadow argument to be `width` times larger than the original input/output.
62+
DualvOnly,
5563
/// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument.
5664
Duplicated,
5765
/// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument.
5866
/// Drop the code which updates the original input for maximum performance.
5967
DuplicatedOnly,
6068
/// All Integers must be Const, but these are used to mark the integer which represents the
6169
/// length of a slice/vec. This is used for safety checks on slices.
62-
FakeActivitySize,
70+
/// The integer (if given) specifies the size of the slice element in bytes.
71+
FakeActivitySize(Option<u32>),
72+
}
73+
74+
impl DiffActivity {
75+
pub fn is_dual_or_const(&self) -> bool {
76+
use DiffActivity::*;
77+
matches!(self, |Dual| DualOnly | Dualv | DualvOnly | Const)
78+
}
6379
}
6480
/// We generate one of these structs for each `#[autodiff(...)]` attribute.
6581
#[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -131,11 +147,7 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
131147
match mode {
132148
DiffMode::Error => false,
133149
DiffMode::Source => false,
134-
DiffMode::Forward => {
135-
activity == DiffActivity::Dual
136-
|| activity == DiffActivity::DualOnly
137-
|| activity == DiffActivity::Const
138-
}
150+
DiffMode::Forward => activity.is_dual_or_const(),
139151
DiffMode::Reverse => {
140152
activity == DiffActivity::Const
141153
|| activity == DiffActivity::Active
@@ -153,10 +165,8 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
153165
pub fn valid_ty_for_activity(ty: &P<Ty>, activity: DiffActivity) -> bool {
154166
use DiffActivity::*;
155167
// It's always allowed to mark something as Const, since we won't compute derivatives wrt. it.
156-
if matches!(activity, Const) {
157-
return true;
158-
}
159-
if matches!(activity, Dual | DualOnly) {
168+
// Dual variants also support all types.
169+
if activity.is_dual_or_const() {
160170
return true;
161171
}
162172
// FIXME(ZuseZ4) We should make this more robust to also
@@ -172,9 +182,7 @@ pub fn valid_input_activity(mode: DiffMode, activity: DiffActivity) -> bool {
172182
return match mode {
173183
DiffMode::Error => false,
174184
DiffMode::Source => false,
175-
DiffMode::Forward => {
176-
matches!(activity, Dual | DualOnly | Const)
177-
}
185+
DiffMode::Forward => activity.is_dual_or_const(),
178186
DiffMode::Reverse => {
179187
matches!(activity, Active | ActiveOnly | Duplicated | DuplicatedOnly | Const)
180188
}
@@ -189,10 +197,12 @@ impl Display for DiffActivity {
189197
DiffActivity::Active => write!(f, "Active"),
190198
DiffActivity::ActiveOnly => write!(f, "ActiveOnly"),
191199
DiffActivity::Dual => write!(f, "Dual"),
200+
DiffActivity::Dualv => write!(f, "Dualv"),
192201
DiffActivity::DualOnly => write!(f, "DualOnly"),
202+
DiffActivity::DualvOnly => write!(f, "DualvOnly"),
193203
DiffActivity::Duplicated => write!(f, "Duplicated"),
194204
DiffActivity::DuplicatedOnly => write!(f, "DuplicatedOnly"),
195-
DiffActivity::FakeActivitySize => write!(f, "FakeActivitySize"),
205+
DiffActivity::FakeActivitySize(s) => write!(f, "FakeActivitySize({:?})", s),
196206
}
197207
}
198208
}
@@ -220,7 +230,9 @@ impl FromStr for DiffActivity {
220230
"ActiveOnly" => Ok(DiffActivity::ActiveOnly),
221231
"Const" => Ok(DiffActivity::Const),
222232
"Dual" => Ok(DiffActivity::Dual),
233+
"Dualv" => Ok(DiffActivity::Dualv),
223234
"DualOnly" => Ok(DiffActivity::DualOnly),
235+
"DualvOnly" => Ok(DiffActivity::DualvOnly),
224236
"Duplicated" => Ok(DiffActivity::Duplicated),
225237
"DuplicatedOnly" => Ok(DiffActivity::DuplicatedOnly),
226238
_ => Err(()),

Diff for: compiler/rustc_builtin_macros/src/autodiff.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -799,8 +799,19 @@ mod llvm_enzyme {
799799
d_inputs.push(shadow_arg.clone());
800800
}
801801
}
802-
DiffActivity::Dual | DiffActivity::DualOnly => {
803-
for i in 0..x.width {
802+
DiffActivity::Dual
803+
| DiffActivity::DualOnly
804+
| DiffActivity::Dualv
805+
| DiffActivity::DualvOnly => {
806+
// the *v variants get lowered to enzyme_dupv and enzyme_dupnoneedv, which cause
807+
// Enzyme to not expect N arguments, but one argument (which is instead larger).
808+
let iterations =
809+
if matches!(activity, DiffActivity::Dualv | DiffActivity::DualvOnly) {
810+
1
811+
} else {
812+
x.width
813+
};
814+
for i in 0..iterations {
804815
let mut shadow_arg = arg.clone();
805816
let old_name = if let PatKind::Ident(_, ident, _) = arg.pat.kind {
806817
ident.name
@@ -823,7 +834,7 @@ mod llvm_enzyme {
823834
DiffActivity::Const => {
824835
// Nothing to do here.
825836
}
826-
DiffActivity::None | DiffActivity::FakeActivitySize => {
837+
DiffActivity::None | DiffActivity::FakeActivitySize(_) => {
827838
panic!("Should not happen");
828839
}
829840
}
@@ -887,8 +898,8 @@ mod llvm_enzyme {
887898
}
888899
};
889900

890-
if let DiffActivity::Dual = x.ret_activity {
891-
let kind = if x.width == 1 {
901+
if matches!(x.ret_activity, DiffActivity::Dual | DiffActivity::Dualv) {
902+
let kind = if x.width == 1 || matches!(x.ret_activity, DiffActivity::Dualv) {
892903
// Dual can only be used for f32/f64 ret.
893904
// In that case we return now a tuple with two floats.
894905
TyKind::Tup(thin_vec![ty.clone(), ty.clone()])
@@ -903,7 +914,7 @@ mod llvm_enzyme {
903914
let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None });
904915
d_decl.output = FnRetTy::Ty(ty);
905916
}
906-
if let DiffActivity::DualOnly = x.ret_activity {
917+
if matches!(x.ret_activity, DiffActivity::DualOnly | DiffActivity::DualvOnly) {
907918
// No need to change the return type,
908919
// we will just return the shadow in place of the primal return.
909920
// However, if we have a width > 1, then we don't return -> T, but -> [T; width]

Diff for: compiler/rustc_codegen_llvm/src/builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
123123
/// Empty string, to be used where LLVM expects an instruction name, indicating
124124
/// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
125125
// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
126-
const UNNAMED: *const c_char = c"".as_ptr();
126+
pub(crate) const UNNAMED: *const c_char = c"".as_ptr();
127127

128128
impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericBuilder<'_, 'll, CX> {
129129
type Value = <GenericCx<'ll, CX> as BackendTypes>::Value;

Diff for: compiler/rustc_codegen_llvm/src/builder/autodiff.rs

+33-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::bug;
1010
use tracing::{debug, trace};
1111

1212
use crate::back::write::llvm_err;
13-
use crate::builder::SBuilder;
13+
use crate::builder::{SBuilder, UNNAMED};
1414
use crate::context::SimpleCx;
1515
use crate::declare::declare_simple_fn;
1616
use crate::errors::{AutoDiffWithoutEnable, LlvmError};
@@ -51,6 +51,7 @@ fn has_sret(fnc: &Value) -> bool {
5151
// using iterators and peek()?
5252
fn match_args_from_caller_to_enzyme<'ll>(
5353
cx: &SimpleCx<'ll>,
54+
builder: &SBuilder<'ll, 'll>,
5455
width: u32,
5556
args: &mut Vec<&'ll llvm::Value>,
5657
inputs: &[DiffActivity],
@@ -78,7 +79,9 @@ fn match_args_from_caller_to_enzyme<'ll>(
7879
let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
7980
let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
8081
let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
82+
let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap();
8183
let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
84+
let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap();
8285

8386
while activity_pos < inputs.len() {
8487
let diff_activity = inputs[activity_pos as usize];
@@ -90,13 +93,34 @@ fn match_args_from_caller_to_enzyme<'ll>(
9093
DiffActivity::Active => (enzyme_out, false),
9194
DiffActivity::ActiveOnly => (enzyme_out, false),
9295
DiffActivity::Dual => (enzyme_dup, true),
96+
DiffActivity::Dualv => (enzyme_dupv, true),
9397
DiffActivity::DualOnly => (enzyme_dupnoneed, true),
98+
DiffActivity::DualvOnly => (enzyme_dupnoneedv, true),
9499
DiffActivity::Duplicated => (enzyme_dup, true),
95100
DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true),
96-
DiffActivity::FakeActivitySize => (enzyme_const, false),
101+
DiffActivity::FakeActivitySize(_) => (enzyme_const, false),
97102
};
98103
let outer_arg = outer_args[outer_pos];
99104
args.push(cx.get_metadata_value(activity));
105+
if matches!(diff_activity, DiffActivity::Dualv) {
106+
let next_outer_arg = outer_args[outer_pos + 1];
107+
let elem_bytes_size: u64 = match inputs[activity_pos + 1] {
108+
DiffActivity::FakeActivitySize(Some(s)) => s.into(),
109+
_ => bug!("incorrect Dualv handling recognized."),
110+
};
111+
// stride: sizeof(T) * n_elems.
112+
// n_elems is the next integer.
113+
// Now we multiply `4 * next_outer_arg` to get the stride.
114+
let mul = unsafe {
115+
llvm::LLVMBuildMul(
116+
builder.llbuilder,
117+
cx.get_const_i64(elem_bytes_size),
118+
next_outer_arg,
119+
UNNAMED,
120+
)
121+
};
122+
args.push(mul);
123+
}
100124
args.push(outer_arg);
101125
if duplicated {
102126
// We know that duplicated args by construction have a following argument,
@@ -114,7 +138,7 @@ fn match_args_from_caller_to_enzyme<'ll>(
114138
} else {
115139
let next_activity = inputs[activity_pos + 1];
116140
// We analyze the MIR types and add this dummy activity if we visit a slice.
117-
next_activity == DiffActivity::FakeActivitySize
141+
matches!(next_activity, DiffActivity::FakeActivitySize(_))
118142
}
119143
};
120144
if slice {
@@ -125,7 +149,10 @@ fn match_args_from_caller_to_enzyme<'ll>(
125149
// int2 >= int1, which means the shadow vector is large enough to store the gradient.
126150
assert_eq!(cx.type_kind(next_outer_ty), TypeKind::Integer);
127151

128-
for i in 0..(width as usize) {
152+
let iterations =
153+
if matches!(diff_activity, DiffActivity::Dualv) { 1 } else { width as usize };
154+
155+
for i in 0..iterations {
129156
let next_outer_arg2 = outer_args[outer_pos + 2 * (i + 1)];
130157
let next_outer_ty2 = cx.val_ty(next_outer_arg2);
131158
assert_eq!(cx.type_kind(next_outer_ty2), TypeKind::Pointer);
@@ -136,7 +163,7 @@ fn match_args_from_caller_to_enzyme<'ll>(
136163
}
137164
args.push(cx.get_metadata_value(enzyme_const));
138165
args.push(next_outer_arg);
139-
outer_pos += 2 + 2 * width as usize;
166+
outer_pos += 2 + 2 * iterations;
140167
activity_pos += 2;
141168
} else {
142169
// A duplicated pointer will have the following two outer_fn arguments:
@@ -360,6 +387,7 @@ fn generate_enzyme_call<'ll>(
360387
let outer_args: Vec<&llvm::Value> = get_params(outer_fn);
361388
match_args_from_caller_to_enzyme(
362389
&cx,
390+
&builder,
363391
attrs.width,
364392
&mut args,
365393
&attrs.input_activity,

Diff for: compiler/rustc_const_eval/src/interpret/eval_context.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
268268

269269
/// Call this on things you got out of the MIR (so it is as generic as the current
270270
/// stack frame), to bring it into the proper environment for this interpreter.
271-
pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions<
271+
pub fn instantiate_from_current_frame_and_normalize_erasing_regions<
272272
T: TypeFoldable<TyCtxt<'tcx>>,
273273
>(
274274
&self,
@@ -279,9 +279,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
279279

280280
/// Call this on things you got out of the MIR (so it is as generic as the provided
281281
/// stack frame), to bring it into the proper environment for this interpreter.
282-
pub(super) fn instantiate_from_frame_and_normalize_erasing_regions<
283-
T: TypeFoldable<TyCtxt<'tcx>>,
284-
>(
282+
pub fn instantiate_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>(
285283
&self,
286284
frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
287285
value: T,

Diff for: compiler/rustc_monomorphize/src/mono_checks/abi_check.rs

+5
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool
111111
}
112112
}
113113

114+
// Zero-sized types are dropped in both ABIs, so they're safe
115+
if arg.layout.is_zst() {
116+
return true;
117+
}
118+
114119
false
115120
}
116121

Diff for: compiler/rustc_monomorphize/src/partitioning/autodiff.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_ast::expand::autodiff_attrs::{AutoDiffItem, DiffActivity};
22
use rustc_hir::def_id::LOCAL_CRATE;
33
use rustc_middle::bug;
44
use rustc_middle::mir::mono::MonoItem;
5-
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
5+
use rustc_middle::ty::{self, Instance, PseudoCanonicalInput, Ty, TyCtxt, TypingEnv};
66
use rustc_symbol_mangling::symbol_name_for_instance_in_crate;
77
use tracing::{debug, trace};
88

@@ -22,23 +22,51 @@ fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec
2222
for (i, ty) in sig.inputs().iter().enumerate() {
2323
if let Some(inner_ty) = ty.builtin_deref(true) {
2424
if inner_ty.is_slice() {
25+
// Now we need to figure out the size of each slice element in memory to allow
26+
// safety checks and usability improvements in the backend.
27+
let sty = match inner_ty.builtin_index() {
28+
Some(sty) => sty,
29+
None => {
30+
panic!("slice element type unknown");
31+
}
32+
};
33+
let pci = PseudoCanonicalInput {
34+
typing_env: TypingEnv::fully_monomorphized(),
35+
value: sty,
36+
};
37+
38+
let layout = tcx.layout_of(pci);
39+
let elem_size = match layout {
40+
Ok(layout) => layout.size,
41+
Err(_) => {
42+
bug!("autodiff failed to compute slice element size");
43+
}
44+
};
45+
let elem_size: u32 = elem_size.bytes() as u32;
46+
2547
// We know that the length will be passed as extra arg.
2648
if !da.is_empty() {
2749
// We are looking at a slice. The length of that slice will become an
2850
// extra integer on llvm level. Integers are always const.
2951
// However, if the slice get's duplicated, we want to know to later check the
3052
// size. So we mark the new size argument as FakeActivitySize.
53+
// There is one FakeActivitySize per slice, so for convenience we store the
54+
// slice element size in bytes in it. We will use the size in the backend.
3155
let activity = match da[i] {
3256
DiffActivity::DualOnly
3357
| DiffActivity::Dual
58+
| DiffActivity::Dualv
3459
| DiffActivity::DuplicatedOnly
35-
| DiffActivity::Duplicated => DiffActivity::FakeActivitySize,
60+
| DiffActivity::Duplicated => {
61+
DiffActivity::FakeActivitySize(Some(elem_size))
62+
}
3663
DiffActivity::Const => DiffActivity::Const,
3764
_ => bug!("unexpected activity for ptr/ref"),
3865
};
3966
new_activities.push(activity);
4067
new_positions.push(i + 1);
4168
}
69+
4270
continue;
4371
}
4472
}

0 commit comments

Comments
 (0)