1use std::cmp::Ordering;
2use std::ffi::c_uint;
3use std::{assert_matches, iter, ptr};
4
5use rustc_abi::{
6 AddressSpace, Align, BackendRepr, CVariadicStatus, Float, HasDataLayout, NumScalableVectors,
7 Primitive, Size, WrappingRange,
8};
9use rustc_codegen_ssa::RetagInfo;
10use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
11use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
12use rustc_codegen_ssa::diagnostics::{ExpectedPointerMutability, InvalidMonomorphization};
13use rustc_codegen_ssa::mir::IntrinsicResult;
14use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
15use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
16use rustc_codegen_ssa::traits::*;
17use rustc_hir as hir;
18use rustc_hir::def_id::LOCAL_CRATE;
19use rustc_hir::find_attr;
20use rustc_lint_defs::builtin::DEPRECATED_LLVM_INTRINSIC;
21use rustc_middle::mir::BinOp;
22use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
23use rustc_middle::ty::offload_meta::OffloadMetadata;
24use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv};
25use rustc_middle::{bug, span_bug};
26use rustc_session::diagnostics::feature_err;
27use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
28use rustc_structures::CrateType;
29use rustc_symbol_mangling::{
30 mangle_internal_symbol, mangle_offload_export, symbol_name_for_instance_in_crate,
31};
32use rustc_target::callconv::PassMode;
33use rustc_target::spec::Arch;
34use tracing::debug;
35
36use crate::abi::FnAbiLlvmExt;
37use crate::builder::Builder;
38use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
39use crate::builder::gpu_offload::{
40 self, OffloadKernelDims, declare_omp_get_num_devices, register_offload,
41};
42use crate::context::CodegenCx;
43use crate::declare::declare_raw_fn;
44use crate::diagnostics::{
45 AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch,
46 OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic,
47};
48use crate::intrinsic::ty::typetree::fnc_typetrees;
49use crate::llvm::{self, Attribute, AttributePlace, Type, Value};
50use crate::type_of::LayoutLlvmExt;
51use crate::va_arg::emit_va_arg;
52
53fn call_simple_intrinsic<'ll, 'tcx>(
54 bx: &mut Builder<'_, 'll, 'tcx>,
55 name: Symbol,
56 args: &[OperandRef<'tcx, &'ll Value>],
57) -> Option<&'ll Value> {
58 let (base_name, type_params): (&'static str, &[&'ll Type]) = match name {
59 sym::sqrtf16 => ("llvm.sqrt", &[bx.type_f16()]),
60 sym::sqrtf32 => ("llvm.sqrt", &[bx.type_f32()]),
61 sym::sqrtf64 => ("llvm.sqrt", &[bx.type_f64()]),
62 sym::sqrtf128 => ("llvm.sqrt", &[bx.type_f128()]),
63
64 sym::powif16 => ("llvm.powi", &[bx.type_f16(), bx.type_i32()]),
65 sym::powif32 => ("llvm.powi", &[bx.type_f32(), bx.type_i32()]),
66 sym::powif64 => ("llvm.powi", &[bx.type_f64(), bx.type_i32()]),
67 sym::powif128 => ("llvm.powi", &[bx.type_f128(), bx.type_i32()]),
68
69 sym::sinf16 => ("llvm.sin", &[bx.type_f16()]),
70 sym::sinf32 => ("llvm.sin", &[bx.type_f32()]),
71 sym::sinf64 => ("llvm.sin", &[bx.type_f64()]),
72 sym::sinf128 => ("llvm.sin", &[bx.type_f128()]),
73
74 sym::cosf16 => ("llvm.cos", &[bx.type_f16()]),
75 sym::cosf32 => ("llvm.cos", &[bx.type_f32()]),
76 sym::cosf64 => ("llvm.cos", &[bx.type_f64()]),
77 sym::cosf128 => ("llvm.cos", &[bx.type_f128()]),
78
79 sym::powf16 => ("llvm.pow", &[bx.type_f16()]),
80 sym::powf32 => ("llvm.pow", &[bx.type_f32()]),
81 sym::powf64 => ("llvm.pow", &[bx.type_f64()]),
82 sym::powf128 => ("llvm.pow", &[bx.type_f128()]),
83
84 sym::expf16 => ("llvm.exp", &[bx.type_f16()]),
85 sym::expf32 => ("llvm.exp", &[bx.type_f32()]),
86 sym::expf64 => ("llvm.exp", &[bx.type_f64()]),
87 sym::expf128 => ("llvm.exp", &[bx.type_f128()]),
88
89 sym::exp2f16 => ("llvm.exp2", &[bx.type_f16()]),
90 sym::exp2f32 => ("llvm.exp2", &[bx.type_f32()]),
91 sym::exp2f64 => ("llvm.exp2", &[bx.type_f64()]),
92 sym::exp2f128 => ("llvm.exp2", &[bx.type_f128()]),
93
94 sym::logf16 => ("llvm.log", &[bx.type_f16()]),
95 sym::logf32 => ("llvm.log", &[bx.type_f32()]),
96 sym::logf64 => ("llvm.log", &[bx.type_f64()]),
97 sym::logf128 => ("llvm.log", &[bx.type_f128()]),
98
99 sym::log10f16 => ("llvm.log10", &[bx.type_f16()]),
100 sym::log10f32 => ("llvm.log10", &[bx.type_f32()]),
101 sym::log10f64 => ("llvm.log10", &[bx.type_f64()]),
102 sym::log10f128 => ("llvm.log10", &[bx.type_f128()]),
103
104 sym::log2f16 => ("llvm.log2", &[bx.type_f16()]),
105 sym::log2f32 => ("llvm.log2", &[bx.type_f32()]),
106 sym::log2f64 => ("llvm.log2", &[bx.type_f64()]),
107 sym::log2f128 => ("llvm.log2", &[bx.type_f128()]),
108
109 sym::fmaf16 => ("llvm.fma", &[bx.type_f16()]),
110 sym::fmaf32 => ("llvm.fma", &[bx.type_f32()]),
111 sym::fmaf64 => ("llvm.fma", &[bx.type_f64()]),
112 sym::fmaf128 => ("llvm.fma", &[bx.type_f128()]),
113
114 sym::fmuladdf16 => ("llvm.fmuladd", &[bx.type_f16()]),
115 sym::fmuladdf32 => ("llvm.fmuladd", &[bx.type_f32()]),
116 sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]),
117 sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]),
118
119 sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]),
120 sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]),
121 sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]),
127 sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]),
128 sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]),
134 sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]),
135 sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]),
136 sym::copysignf128 => ("llvm.copysign", &[bx.type_f128()]),
137
138 sym::floorf16 => ("llvm.floor", &[bx.type_f16()]),
139 sym::floorf32 => ("llvm.floor", &[bx.type_f32()]),
140 sym::floorf64 => ("llvm.floor", &[bx.type_f64()]),
141 sym::floorf128 => ("llvm.floor", &[bx.type_f128()]),
142
143 sym::ceilf16 => ("llvm.ceil", &[bx.type_f16()]),
144 sym::ceilf32 => ("llvm.ceil", &[bx.type_f32()]),
145 sym::ceilf64 => ("llvm.ceil", &[bx.type_f64()]),
146 sym::ceilf128 => ("llvm.ceil", &[bx.type_f128()]),
147
148 sym::truncf16 => ("llvm.trunc", &[bx.type_f16()]),
149 sym::truncf32 => ("llvm.trunc", &[bx.type_f32()]),
150 sym::truncf64 => ("llvm.trunc", &[bx.type_f64()]),
151 sym::truncf128 => ("llvm.trunc", &[bx.type_f128()]),
152
153 sym::round_ties_even_f16 => ("llvm.rint", &[bx.type_f16()]),
158 sym::round_ties_even_f32 => ("llvm.rint", &[bx.type_f32()]),
159 sym::round_ties_even_f64 => ("llvm.rint", &[bx.type_f64()]),
160 sym::round_ties_even_f128 => ("llvm.rint", &[bx.type_f128()]),
161
162 sym::roundf16 => ("llvm.round", &[bx.type_f16()]),
163 sym::roundf32 => ("llvm.round", &[bx.type_f32()]),
164 sym::roundf64 => ("llvm.round", &[bx.type_f64()]),
165 sym::roundf128 => ("llvm.round", &[bx.type_f128()]),
166
167 _ => return None,
168 };
169 Some(bx.call_intrinsic(
170 base_name,
171 type_params,
172 &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
173 ))
174}
175
176impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
177 fn codegen_intrinsic_call(
178 &mut self,
179 instance: ty::Instance<'tcx>,
180 args: &[OperandRef<'tcx, &'ll Value>],
181 result_layout: ty::layout::TyAndLayout<'tcx>,
182 result_place: Option<PlaceValue<&'ll Value>>,
183 span: Span,
184 ) -> IntrinsicResult<'tcx, &'ll Value> {
185 let tcx = self.tcx;
186 let llvm_version = crate::llvm_util::get_version();
187
188 let name = tcx.item_name(instance.def_id());
189 let fn_args = instance.args;
190
191 let simple = call_simple_intrinsic(self, name, args);
192 let llval = match name {
193 _ if simple.is_some() => simple.unwrap(),
194 sym::minimum_number_nsz_f16
195 | sym::minimum_number_nsz_f32
196 | sym::minimum_number_nsz_f64
197 | sym::minimum_number_nsz_f128
198 | sym::maximum_number_nsz_f16
199 | sym::maximum_number_nsz_f32
200 | sym::maximum_number_nsz_f64
201 | sym::maximum_number_nsz_f128
202 if llvm_version >= (22, 0, 0) =>
204 {
205 let intrinsic_name = if name.as_str().starts_with("min") {
206 "llvm.minimumnum"
207 } else {
208 "llvm.maximumnum"
209 };
210 let call = self.call_intrinsic(
211 intrinsic_name,
212 &[args[0].layout.immediate_llvm_type(self.cx)],
213 &[args[0].immediate(), args[1].immediate()],
214 );
215 unsafe { llvm::LLVMRustSetNoSignedZeros(call) };
218 call
219 }
220 sym::ptr_mask => {
221 let ptr = args[0].immediate();
222 self.call_intrinsic(
223 "llvm.ptrmask",
224 &[self.val_ty(ptr), self.type_isize()],
225 &[ptr, args[1].immediate()],
226 )
227 }
228 sym::autodiff => {
229 return codegen_autodiff(self, instance, args, result_layout, result_place);
230 }
231 sym::offload => {
232 if tcx.sess.opts.unstable_opts.offload.is_empty() {
233 let _ = tcx.dcx().emit_almost_fatal(OffloadWithoutEnable);
234 }
235
236 if tcx.sess.lto() != rustc_session::config::Lto::Fat {
237 let _ = tcx.dcx().emit_almost_fatal(OffloadWithoutFatLTO);
238 }
239
240 codegen_offload(self, tcx, instance, args);
241 return IntrinsicResult::WroteIntoPlace;
243 }
244 sym::offload_get_num_devices => {
245 let (fn_decl, fn_ty) = declare_omp_get_num_devices(self.cx);
246
247 let llval = self.call(fn_ty, None, None, fn_decl, &[], None, None);
248
249 return IntrinsicResult::Operand(OperandValue::Immediate(llval));
250 },
251 sym::is_val_statically_known => {
252 if let OperandValue::Immediate(imm) = args[0].val {
253 self.call_intrinsic(
254 "llvm.is.constant",
255 &[args[0].layout.immediate_llvm_type(self.cx)],
256 &[imm],
257 )
258 } else {
259 self.const_bool(false)
260 }
261 }
262 sym::select_unpredictable => {
263 let cond = args[0].immediate();
264 {
match (&args[1].layout, &args[2].layout) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(args[1].layout, args[2].layout);
265 let select = |bx: &mut Self, true_val, false_val| {
266 let result = bx.select(cond, true_val, false_val);
267 bx.set_unpredictable(&result);
268 result
269 };
270 match (args[1].val, args[2].val) {
271 (OperandValue::Ref(true_val), OperandValue::Ref(false_val)) => {
272 if !true_val.llextra.is_none() {
::core::panicking::panic("assertion failed: true_val.llextra.is_none()")
};assert!(true_val.llextra.is_none());
273 if !false_val.llextra.is_none() {
::core::panicking::panic("assertion failed: false_val.llextra.is_none()")
};assert!(false_val.llextra.is_none());
274 {
match (&true_val.align, &false_val.align) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(true_val.align, false_val.align);
275 let ptr = select(self, true_val.llval, false_val.llval);
276 let selected =
277 OperandValue::Ref(PlaceValue::new_sized(ptr, true_val.align));
278 let result = PlaceRef {
279 val: result_place.unwrap(),
280 layout: result_layout,
281 };
282 selected.store(self, result);
283 return IntrinsicResult::WroteIntoPlace;
284 }
285 (OperandValue::Immediate(_), OperandValue::Immediate(_))
286 | (OperandValue::Pair(_, _), OperandValue::Pair(_, _)) => {
287 let true_val = args[1].immediate_or_packed_pair(self);
288 let false_val = args[2].immediate_or_packed_pair(self);
289 select(self, true_val, false_val)
290 }
291 (OperandValue::ZeroSized, OperandValue::ZeroSized) => return IntrinsicResult::Operand(OperandValue::ZeroSized),
292 _ => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("Incompatible OperandValue for select_unpredictable"))span_bug!(span, "Incompatible OperandValue for select_unpredictable"),
293 }
294 }
295 sym::catch_unwind => {
296 catch_unwind_intrinsic(
297 self,
298 args[0].immediate(),
299 args[1].immediate(),
300 args[2].immediate(),
301 )
302 }
303 sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
304 sym::va_arg => {
305 let target = &self.cx.tcx.sess.target;
306 let stability = target.supports_c_variadic_definitions();
307 if let CVariadicStatus::Unstable { feature } = stability
308 && !self.tcx.features().enabled(feature)
309 {
310 let msg =
311 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("C-variadic function definitions on this target are unstable"))
})format!("C-variadic function definitions on this target are unstable");
312 feature_err(&*self.sess(), feature, span, msg).emit();
313 }
314
315 let BackendRepr::Scalar(scalar) = result_layout.backend_repr else {
316 ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support non-scalar types"))bug!("the va_arg intrinsic does not support non-scalar types")
317 };
318
319 match scalar.primitive() {
323 Primitive::Pointer(_) => {
324 }
326 Primitive::Int(..) => {
327 let int_width = self.cx().size_of(result_layout.ty).bits();
328 let target_c_int_width = self.cx().sess().target.options.c_int_width;
329 if int_width < u64::from(target_c_int_width) {
330 ::rustc_middle::util::bug::bug_fmt(format_args!("va_arg got i{0} but needs at least c_int (an i{1})",
int_width, target_c_int_width));bug!(
333 "va_arg got i{} but needs at least c_int (an i{})",
334 int_width,
335 target_c_int_width
336 );
337 }
338 }
339 Primitive::Float(Float::F16) => {
340 ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support `f16`"))bug!("the va_arg intrinsic does not support `f16`")
341 }
342 Primitive::Float(Float::F32) => {
343 if self.cx().sess().target.arch != Arch::Avr {
345 ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support `f32` on this target"))bug!("the va_arg intrinsic does not support `f32` on this target")
346 }
347 }
348 Primitive::Float(Float::F64) => {
349 }
351 Primitive::Float(Float::F128) => {
352 ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support `f128`"))bug!("the va_arg intrinsic does not support `f128`")
354 }
355 }
356
357 emit_va_arg(self, args[0], result_layout.ty)
358 }
359
360 sym::volatile_load | sym::unaligned_volatile_load => {
361 let ptr = args[0].immediate();
366 let abi_align = result_layout.align.abi;
367 let ptr_align = if name == sym::volatile_load { abi_align } else { Align::ONE };
368 if result_layout.is_zst() {
369 return IntrinsicResult::Operand(OperandValue::ZeroSized);
370 } else if let BackendRepr::Scalar(scalar) = result_layout.backend_repr {
371 let load = self.volatile_load(self.type_from_scalar(scalar), ptr, ptr_align);
372 self.to_immediate_scalar(load, scalar)
373 } else {
374 let llty = self.type_ix(result_layout.size.bits());
378 let temp = if let Some(result_place) = result_place {
379 PlaceRef {
380 val: result_place,
381 layout: result_layout,
382 }
383 } else {
384 PlaceRef::alloca(self, result_layout)
385 };
386 let llval = self.volatile_load(llty, ptr, ptr_align);
387 self.store(llval, temp.val.llval, abi_align);
388 return if result_place.is_none() {
389 IntrinsicResult::Operand(self.load_operand(temp).val)
390 } else {
391 IntrinsicResult::WroteIntoPlace
392 };
393 }
394 }
395 sym::prefetch_read_data
396 | sym::prefetch_write_data
397 | sym::prefetch_read_instruction
398 | sym::prefetch_write_instruction => {
399 let (rw, cache_type) = match name {
400 sym::prefetch_read_data => (0, 1),
401 sym::prefetch_write_data => (1, 1),
402 sym::prefetch_read_instruction => (0, 0),
403 sym::prefetch_write_instruction => (1, 0),
404 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
405 };
406 let ptr = args[0].immediate();
407 let locality = fn_args.const_at(1).to_leaf().to_i32();
408 self.call_intrinsic(
409 "llvm.prefetch.p0",
410 &[self.val_ty(ptr)],
411 &[
412 ptr,
413 self.const_i32(rw),
414 self.const_i32(locality),
415 self.const_i32(cache_type),
416 ],
417 );
418 return IntrinsicResult::Operand(OperandValue::ZeroSized);
419 }
420 sym::carrying_mul_add => {
421 let (size, signed) = fn_args.type_at(0).int_size_and_signed(self.tcx);
422
423 let wide_llty = self.type_ix(size.bits() * 2);
424 let args = args.as_array().unwrap();
425 let [a, b, c, d] = args.map(|a| self.intcast(a.immediate(), wide_llty, signed));
426
427 let wide = if signed {
428 let prod = self.unchecked_smul(a, b);
429 let acc = self.unchecked_sadd(prod, c);
430 self.unchecked_sadd(acc, d)
431 } else {
432 let prod = self.unchecked_umul(a, b);
433 let acc = self.unchecked_uadd(prod, c);
434 self.unchecked_uadd(acc, d)
435 };
436
437 let narrow_llty = self.type_ix(size.bits());
438 let low = self.trunc(wide, narrow_llty);
439 let bits_const = self.const_uint(wide_llty, size.bits());
440 let high = self.lshr(wide, bits_const);
442 let high = self.trunc(high, narrow_llty);
444
445 let pair_llty = self.type_struct(&[narrow_llty, narrow_llty], false);
446 let pair = self.const_poison(pair_llty);
447 let pair = self.insert_value(pair, low, 0);
448 let pair = self.insert_value(pair, high, 1);
449 pair
450 }
451
452 sym::carryless_mul if llvm_version >= (22, 0, 0) => {
454 let ty = args[0].layout.ty;
455 if !ty.is_integral() {
456 let err = tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
457 span,
458 name,
459 ty,
460 });
461 return IntrinsicResult::Err(err);
462 }
463 let (size, _) = ty.int_size_and_signed(self.tcx);
464 let width = size.bits();
465 let llty = self.type_ix(width);
466
467 let lhs = args[0].immediate();
468 let rhs = args[1].immediate();
469 self.call_intrinsic("llvm.clmul", &[llty], &[lhs, rhs])
470 }
471
472 sym::ctlz
473 | sym::ctlz_nonzero
474 | sym::cttz
475 | sym::cttz_nonzero
476 | sym::ctpop
477 | sym::bswap
478 | sym::bitreverse
479 | sym::saturating_add
480 | sym::saturating_sub
481 | sym::unchecked_funnel_shl
482 | sym::unchecked_funnel_shr => {
483 let ty = args[0].layout.ty;
484 if !ty.is_integral() {
485 let err = tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
486 span,
487 name,
488 ty,
489 });
490 return IntrinsicResult::Err(err);
491 }
492 let (size, signed) = ty.int_size_and_signed(self.tcx);
493 let width = size.bits();
494 let llty = self.type_ix(width);
495 match name {
496 sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => {
497 let y =
498 self.const_bool(name == sym::ctlz_nonzero || name == sym::cttz_nonzero);
499 let llvm_name = if name == sym::ctlz || name == sym::ctlz_nonzero {
500 "llvm.ctlz"
501 } else {
502 "llvm.cttz"
503 };
504 let ret =
505 self.call_intrinsic(llvm_name, &[llty], &[args[0].immediate(), y]);
506 self.intcast(ret, result_layout.llvm_type(self), false)
507 }
508 sym::ctpop => {
509 let ret =
510 self.call_intrinsic("llvm.ctpop", &[llty], &[args[0].immediate()]);
511 self.intcast(ret, result_layout.llvm_type(self), false)
512 }
513 sym::bswap => {
514 if width == 8 {
515 args[0].immediate() } else {
517 self.call_intrinsic("llvm.bswap", &[llty], &[args[0].immediate()])
518 }
519 }
520 sym::bitreverse => {
521 self.call_intrinsic("llvm.bitreverse", &[llty], &[args[0].immediate()])
522 }
523 sym::unchecked_funnel_shl | sym::unchecked_funnel_shr => {
524 let is_left = name == sym::unchecked_funnel_shl;
525 let lhs = args[0].immediate();
526 let rhs = args[1].immediate();
527 let raw_shift = args[2].immediate();
528 let llvm_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("llvm.fsh{0}",
if is_left { 'l' } else { 'r' }))
})format!("llvm.fsh{}", if is_left { 'l' } else { 'r' });
529
530 let raw_shift = self.intcast(raw_shift, self.val_ty(lhs), false);
533
534 self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs, raw_shift])
535 }
536 sym::saturating_add | sym::saturating_sub => {
537 let is_add = name == sym::saturating_add;
538 let lhs = args[0].immediate();
539 let rhs = args[1].immediate();
540 let llvm_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("llvm.{0}{1}.sat",
if signed { 's' } else { 'u' },
if is_add { "add" } else { "sub" }))
})format!(
541 "llvm.{}{}.sat",
542 if signed { 's' } else { 'u' },
543 if is_add { "add" } else { "sub" },
544 );
545 self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs])
546 }
547 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
548 }
549 }
550
551 sym::fabs => {
552 let ty = args[0].layout.ty;
553 let ty::Float(f) = ty.kind() else {
554 ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("the `fabs` intrinsic requires a floating-point argument, got {0:?}",
ty));span_bug!(span, "the `fabs` intrinsic requires a floating-point argument, got {:?}", ty);
555 };
556 let llty = self.type_float_from_ty(*f);
557 let llvm_name = "llvm.fabs";
558 self.call_intrinsic(
559 llvm_name,
560 &[llty],
561 &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
562 )
563 }
564
565 sym::raw_eq => {
566 use BackendRepr::*;
567 let tp_ty = fn_args.type_at(0);
568 let layout = self.layout_of(tp_ty).layout;
569 let use_integer_compare = match layout.backend_repr() {
570 Scalar(_) | ScalarPair { a: _, b: _, b_offset: _ } => true,
571 SimdVector { .. } => false,
572 SimdScalableVector { .. } => {
573 let err = tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType {
574 span,
575 name: sym::raw_eq,
576 ty: tp_ty,
577 });
578 return IntrinsicResult::Err(err);
579 }
580 Memory { .. } => {
581 layout.size() <= self.data_layout().pointer_size() * 2
585 }
586 };
587
588 let a = args[0].immediate();
589 let b = args[1].immediate();
590 if layout.size().bytes() == 0 {
591 self.const_bool(true)
592 } else if use_integer_compare {
593 let integer_ty = self.type_ix(layout.size().bits());
594 let a_val = self.load(integer_ty, a, layout.align().abi);
595 let b_val = self.load(integer_ty, b, layout.align().abi);
596 self.icmp(IntPredicate::IntEQ, a_val, b_val)
597 } else {
598 let n = self.const_usize(layout.size().bytes());
599 let cmp = self.call_intrinsic("memcmp", &[], &[a, b, n]);
600 self.icmp(IntPredicate::IntEQ, cmp, self.const_int(self.type_int(), 0))
601 }
602 }
603
604 sym::compare_bytes => {
605 let cmp = self.call_intrinsic(
607 "memcmp",
608 &[],
609 &[args[0].immediate(), args[1].immediate(), args[2].immediate()],
610 );
611 self.sext(cmp, self.type_ix(32))
613 }
614
615 sym::black_box => {
616 let result = PlaceRef {
617 val: result_place.unwrap(),
618 layout: result_layout,
619 };
620 args[0].val.store(self, result);
621 let result_val_span = [result.val.llval];
622 let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() {
632 ("~{memory}", &[])
633 } else {
634 ("r,~{memory}", &result_val_span)
635 };
636 crate::asm::inline_asm_call(
637 self,
638 "",
639 constraint,
640 inputs,
641 self.type_void(),
642 &[],
643 true,
644 false,
645 llvm::AsmDialect::Att,
646 &[span],
647 false,
648 None,
649 None,
650 )
651 .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("failed to generate inline asm call for `black_box`"))bug!("failed to generate inline asm call for `black_box`"));
652
653 return IntrinsicResult::WroteIntoPlace;
655 }
656
657 sym::gpu_launch_sized_workgroup_mem => {
658 let name = if llvm_version < (23, 0, 0) && tcx.sess.target.arch == Arch::Nvptx64 {
666 "gpu_launch_sized_workgroup_mem"
670 } else {
671 ""
672 };
673 let global = self.declare_global_in_addrspace(
674 name,
675 self.type_array(self.type_i8(), 0),
676 AddressSpace::GPU_WORKGROUP,
677 );
678 let ty::RawPtr(inner_ty, _) = result_layout.ty.kind() else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
679 let alignment = self.align_of(*inner_ty).bytes() as u32;
684 unsafe {
685 if tcx.sess.target.arch == Arch::Nvptx64 {
687 if alignment > llvm::LLVMGetAlignment(global) {
688 llvm::LLVMSetAlignment(global, alignment);
689 }
690 } else {
691 llvm::LLVMSetAlignment(global, alignment);
692 }
693 }
694 self.cx().const_pointercast(global, self.type_ptr())
695 }
696
697 sym::amdgpu_dispatch_ptr => {
698 let val = self.call_intrinsic("llvm.amdgcn.dispatch.ptr", &[], &[]);
699 self.pointercast(val, self.type_ptr())
701 }
702
703 sym::sve_tuple_create2 => {
704 {
match self.layout_of(fn_args.type_at(0)).backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(1), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
705 self.layout_of(fn_args.type_at(0)).backend_repr,
706 BackendRepr::SimdScalableVector {
707 number_of_vectors: NumScalableVectors(1),
708 ..
709 }
710 );
711 let tuple_ty = self.layout_of(fn_args.type_at(1));
712 {
match tuple_ty.backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(2), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(2), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
713 tuple_ty.backend_repr,
714 BackendRepr::SimdScalableVector {
715 number_of_vectors: NumScalableVectors(2),
716 ..
717 }
718 );
719 let ret = self.const_poison(self.backend_type(tuple_ty));
720 let ret = self.insert_value(ret, args[0].immediate(), 0);
721 self.insert_value(ret, args[1].immediate(), 1)
722 }
723
724 sym::sve_tuple_create3 => {
725 {
match self.layout_of(fn_args.type_at(0)).backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(1), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
726 self.layout_of(fn_args.type_at(0)).backend_repr,
727 BackendRepr::SimdScalableVector {
728 number_of_vectors: NumScalableVectors(1),
729 ..
730 }
731 );
732 let tuple_ty = self.layout_of(fn_args.type_at(1));
733 {
match tuple_ty.backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(3), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(3), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
734 tuple_ty.backend_repr,
735 BackendRepr::SimdScalableVector {
736 number_of_vectors: NumScalableVectors(3),
737 ..
738 }
739 );
740 let ret = self.const_poison(self.backend_type(tuple_ty));
741 let ret = self.insert_value(ret, args[0].immediate(), 0);
742 let ret = self.insert_value(ret, args[1].immediate(), 1);
743 self.insert_value(ret, args[2].immediate(), 2)
744 }
745
746 sym::sve_tuple_create4 => {
747 {
match self.layout_of(fn_args.type_at(0)).backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(1), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
748 self.layout_of(fn_args.type_at(0)).backend_repr,
749 BackendRepr::SimdScalableVector {
750 number_of_vectors: NumScalableVectors(1),
751 ..
752 }
753 );
754 let tuple_ty = self.layout_of(fn_args.type_at(1));
755 {
match tuple_ty.backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(4), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(4), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
756 tuple_ty.backend_repr,
757 BackendRepr::SimdScalableVector {
758 number_of_vectors: NumScalableVectors(4),
759 ..
760 }
761 );
762 let ret = self.const_poison(self.backend_type(tuple_ty));
763 let ret = self.insert_value(ret, args[0].immediate(), 0);
764 let ret = self.insert_value(ret, args[1].immediate(), 1);
765 let ret = self.insert_value(ret, args[2].immediate(), 2);
766 self.insert_value(ret, args[3].immediate(), 3)
767 }
768
769 sym::sve_tuple_get => {
770 {
match self.layout_of(fn_args.type_at(0)).backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
.. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
771 self.layout_of(fn_args.type_at(0)).backend_repr,
772 BackendRepr::SimdScalableVector {
773 number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
774 ..
775 }
776 );
777 {
match self.layout_of(fn_args.type_at(1)).backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(1), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
778 self.layout_of(fn_args.type_at(1)).backend_repr,
779 BackendRepr::SimdScalableVector {
780 number_of_vectors: NumScalableVectors(1),
781 ..
782 }
783 );
784 self.extract_value(
785 args[0].immediate(),
786 fn_args.const_at(2).to_leaf().to_i32() as u64,
787 )
788 }
789
790 sym::sve_tuple_set => {
791 {
match self.layout_of(fn_args.type_at(0)).backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
.. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
792 self.layout_of(fn_args.type_at(0)).backend_repr,
793 BackendRepr::SimdScalableVector {
794 number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
795 ..
796 }
797 );
798 {
match self.layout_of(fn_args.type_at(1)).backend_repr {
BackendRepr::SimdScalableVector {
number_of_vectors: NumScalableVectors(1), .. } => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
::core::option::Option::None);
}
}
};assert_matches!(
799 self.layout_of(fn_args.type_at(1)).backend_repr,
800 BackendRepr::SimdScalableVector {
801 number_of_vectors: NumScalableVectors(1),
802 ..
803 }
804 );
805 self.insert_value(
806 args[0].immediate(),
807 args[1].immediate(),
808 fn_args.const_at(2).to_leaf().to_i32() as u64,
809 )
810 }
811
812 _ if name.as_str().starts_with("simd_") => {
813 let mut loaded_args = Vec::new();
816 for arg in args {
817 loaded_args.push(
818 if arg.layout.ty.is_simd()
823 && let OperandValue::Ref(place) = arg.val
824 {
825 let (size, elem_ty) = arg.layout.ty.simd_size_and_type(self.tcx());
826 let elem_ll_ty = match elem_ty.kind() {
827 ty::Float(f) => self.type_float_from_ty(*f),
828 ty::Int(i) => self.type_int_from_ty(*i),
829 ty::Uint(u) => self.type_uint_from_ty(*u),
830 ty::RawPtr(_, _) => self.type_ptr(),
831 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
832 };
833 let loaded =
834 self.load_from_place(self.type_vector(elem_ll_ty, size), place);
835 OperandRef::from_immediate_or_packed_pair(self, loaded, arg.layout)
836 } else {
837 *arg
838 },
839 );
840 }
841
842 let llret_ty = if result_layout.ty.is_simd()
843 && let BackendRepr::Memory { .. } = result_layout.backend_repr
844 {
845 let (size, elem_ty) = result_layout.ty.simd_size_and_type(self.tcx());
846 let elem_ll_ty = match elem_ty.kind() {
847 ty::Float(f) => self.type_float_from_ty(*f),
848 ty::Int(i) => self.type_int_from_ty(*i),
849 ty::Uint(u) => self.type_uint_from_ty(*u),
850 ty::RawPtr(_, _) => self.type_ptr(),
851 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
852 };
853 self.type_vector(elem_ll_ty, size)
854 } else {
855 result_layout.llvm_type(self)
856 };
857
858 match generic_simd_intrinsic(
859 self,
860 name,
861 fn_args,
862 &loaded_args,
863 result_layout.ty,
864 llret_ty,
865 span,
866 ) {
867 Ok(llval) => llval,
868 Err(err) => return IntrinsicResult::Err(err),
871 }
872 }
873
874 sym::return_address => {
875 match self.sess().target.arch {
876 | Arch::Wasm32
878 | Arch::Wasm64 => {
879 let ty = self.type_ptr();
880 self.const_null(ty)
881 }
882 _ => {
883 let ty = self.type_ix(32);
884 let val = self.const_int(ty, 0);
885
886 let type_params: &[&'ll Type] = if llvm_version < (23, 0, 0) {
887 &[]
888 } else {
889 &[self.type_ptr()]
890 };
891
892 self.call_intrinsic("llvm.returnaddress", type_params, &[val])
893 }
894 }
895 }
896
897 _ => {
898 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/intrinsic.rs:898",
"rustc_codegen_llvm::intrinsic", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/intrinsic.rs"),
::tracing_core::__macro_support::Option::Some(898u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::intrinsic"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("unknown intrinsic \'{0}\' -- falling back to default body",
name) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("unknown intrinsic '{}' -- falling back to default body", name);
899 let fallback = ty::Instance::new_raw(instance.def_id(), instance.args);
901 return IntrinsicResult::Fallback(fallback);
902 }
903 };
904
905 if let BackendRepr::Memory { .. } = result_layout.backend_repr {
906 if !result_layout.is_zst() {
909 self.store_to_place(llval, result_place.unwrap());
910 }
911 IntrinsicResult::WroteIntoPlace
912 } else {
913 IntrinsicResult::Operand(
914 OperandRef::from_immediate_or_packed_pair(self, llval, result_layout).val,
915 )
916 }
917 }
918
919 fn codegen_llvm_intrinsic_call(
920 &mut self,
921 instance: ty::Instance<'tcx>,
922 args: &[OperandRef<'tcx, Self::Value>],
923 _is_cleanup: bool,
924 ) -> Self::Value {
925 let tcx = self.tcx();
926
927 let fn_ty = instance.ty(tcx, self.typing_env());
928 let fn_sig = match *fn_ty.kind() {
929 ty::FnDef(def_id, args) => tcx.instantiate_bound_regions_with_erased(
930 tcx.fn_sig(def_id).instantiate(tcx, args.no_bound_vars().unwrap()).skip_norm_wip(),
931 ),
932 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
933 };
934 if !!fn_sig.c_variadic() {
::core::panicking::panic("assertion failed: !fn_sig.c_variadic()")
};assert!(!fn_sig.c_variadic());
935
936 let ret_layout = self.layout_of(fn_sig.output());
937 let llreturn_ty = if ret_layout.is_zst() {
938 self.type_void()
939 } else {
940 ret_layout.immediate_llvm_type(self)
941 };
942
943 let mut llargument_tys = Vec::with_capacity(fn_sig.inputs().len());
944 for &arg in fn_sig.inputs() {
945 let arg_layout = self.layout_of(arg);
946 if arg_layout.is_zst() {
947 continue;
948 }
949 llargument_tys.push(arg_layout.immediate_llvm_type(self));
950 }
951
952 let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) {
953 llfn
954 } else {
955 let sym = tcx.symbol_name(instance).name;
956
957 let llfn = if let Some(llfn) = self.get_declared_value(sym) {
958 llfn
959 } else {
960 intrinsic_fn(self, sym, llreturn_ty, llargument_tys, instance)
961 };
962
963 self.intrinsic_instances.borrow_mut().insert(instance, llfn);
964
965 llfn
966 };
967 let fn_ty = self.get_type_of_global(fn_ptr);
968
969 let mut llargs = ::alloc::vec::Vec::new()vec![];
970
971 for arg in args {
972 match arg.val {
973 OperandValue::ZeroSized => {}
974 OperandValue::Immediate(a) => llargs.push(a),
975 OperandValue::Pair(a, b) => {
976 llargs.push(a);
977 llargs.push(b);
978 }
979 OperandValue::Ref(op_place_val) => {
980 let mut llval = op_place_val.llval;
981 llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
987 if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
988 if scalar.is_bool() {
989 self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
990 }
991 llval = self.to_immediate_scalar(llval, scalar);
993 }
994 llargs.push(llval);
995 }
996 }
997 }
998
999 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/intrinsic.rs:999",
"rustc_codegen_llvm::intrinsic", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/intrinsic.rs"),
::tracing_core::__macro_support::Option::Some(999u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::intrinsic"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("call intrinsic {0:?} with args ({1:?})",
instance, llargs) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("call intrinsic {:?} with args ({:?})", instance, llargs);
1000
1001 for (dest_ty, arg) in iter::zip(self.func_params_types(fn_ty), &mut llargs) {
1002 let src_ty = self.val_ty(arg);
1003 if !can_autocast(self, src_ty, dest_ty) {
{
::core::panicking::panic_fmt(format_args!("Cannot match `{0:?}` (expected) with {1:?} (found) in `{2:?}",
dest_ty, src_ty, fn_ptr));
}
};assert!(
1004 can_autocast(self, src_ty, dest_ty),
1005 "Cannot match `{dest_ty:?}` (expected) with {src_ty:?} (found) in `{fn_ptr:?}"
1006 );
1007
1008 *arg = autocast(self, arg, src_ty, dest_ty);
1009 }
1010
1011 let llret = unsafe {
1012 llvm::LLVMBuildCallWithOperandBundles(
1013 self.llbuilder,
1014 fn_ty,
1015 fn_ptr,
1016 llargs.as_ptr(),
1017 llargs.len() as c_uint,
1018 ptr::dangling(),
1019 0,
1020 c"".as_ptr(),
1021 )
1022 };
1023
1024 let src_ty = self.val_ty(llret);
1025 let dest_ty = llreturn_ty;
1026 if !can_autocast(self, dest_ty, src_ty) {
{
::core::panicking::panic_fmt(format_args!("Cannot match `{0:?}` (expected) with `{1:?}` (found) in `{2:?}`",
src_ty, dest_ty, fn_ptr));
}
};assert!(
1027 can_autocast(self, dest_ty, src_ty),
1028 "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`"
1029 );
1030
1031 autocast(self, llret, src_ty, dest_ty)
1032 }
1033
1034 fn abort(&mut self) {
1035 self.call_intrinsic("llvm.trap", &[], &[]);
1036 }
1037
1038 fn assume(&mut self, val: Self::Value) {
1039 if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
1040 self.call_intrinsic("llvm.assume", &[], &[val]);
1041 }
1042 }
1043
1044 fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
1045 if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
1046 self.call_intrinsic(
1047 "llvm.expect",
1048 &[self.type_i1()],
1049 &[cond, self.const_bool(expected)],
1050 )
1051 } else {
1052 cond
1053 }
1054 }
1055
1056 fn type_checked_load(
1057 &mut self,
1058 llvtable: &'ll Value,
1059 vtable_byte_offset: u64,
1060 typeid: &[u8],
1061 ) -> Self::Value {
1062 let typeid = self.create_metadata(typeid);
1063 let typeid = self.get_metadata_value(typeid);
1064 let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
1065 let type_checked_load = self.call_intrinsic(
1066 "llvm.type.checked.load",
1067 &[],
1068 &[llvtable, vtable_byte_offset, typeid],
1069 );
1070 self.extract_value(type_checked_load, 0)
1071 }
1072
1073 fn va_start(&mut self, va_list: &'ll Value) {
1074 self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list]);
1075 }
1076
1077 fn retag_reg(&mut self, ptr: Self::Value, info: &RetagInfo<Self::Value>) -> Self::Value {
1078 codegen_retag_inner(self, "__rust_retag_reg", ptr, info)
1079 }
1080
1081 fn retag_mem(&mut self, ptr: Self::Value, info: &RetagInfo<Self::Value>) {
1082 codegen_retag_inner(self, "__rust_retag_mem", ptr, info);
1083 }
1084}
1085
1086fn llvm_arch_for(rust_arch: &Arch) -> Option<&'static str> {
1087 Some(match rust_arch {
1088 Arch::AArch64 | Arch::Arm64EC => "aarch64",
1089 Arch::AmdGpu => "amdgcn",
1090 Arch::Arm => "arm",
1091 Arch::Bpf => "bpf",
1092 Arch::Hexagon => "hexagon",
1093 Arch::LoongArch32 | Arch::LoongArch64 => "loongarch",
1094 Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => "mips",
1095 Arch::Nvptx64 => "nvvm",
1096 Arch::PowerPC | Arch::PowerPC64 => "ppc",
1097 Arch::RiscV32 | Arch::RiscV64 => "riscv",
1098 Arch::S390x => "s390",
1099 Arch::SpirV => "spv",
1100 Arch::Wasm32 | Arch::Wasm64 => "wasm",
1101 Arch::X86 | Arch::X86_64 => "x86",
1102 _ => return None, })
1104}
1105
1106fn can_autocast<'ll>(cx: &CodegenCx<'ll, '_>, rust_ty: &'ll Type, llvm_ty: &'ll Type) -> bool {
1107 if rust_ty == llvm_ty {
1108 return true;
1109 }
1110
1111 match cx.type_kind(llvm_ty) {
1112 TypeKind::Struct if cx.type_kind(rust_ty) == TypeKind::Struct => {
1116 let rust_element_tys = cx.struct_element_types(rust_ty);
1117 let llvm_element_tys = cx.struct_element_types(llvm_ty);
1118
1119 if rust_element_tys.len() != llvm_element_tys.len() {
1120 return false;
1121 }
1122
1123 iter::zip(rust_element_tys, llvm_element_tys).all(
1124 |(rust_element_ty, llvm_element_ty)| {
1125 can_autocast(cx, rust_element_ty, llvm_element_ty)
1126 },
1127 )
1128 }
1129 TypeKind::Vector => {
1130 let llvm_element_ty = cx.element_type(llvm_ty);
1131 let element_count = cx.vector_length(llvm_ty) as u64;
1132
1133 if llvm_element_ty == cx.type_bf16() {
1134 rust_ty == cx.type_vector(cx.type_i16(), element_count)
1135 } else if llvm_element_ty == cx.type_i1() {
1136 let int_width = element_count.next_power_of_two().max(8);
1137 rust_ty == cx.type_ix(int_width)
1138 } else {
1139 false
1140 }
1141 }
1142 TypeKind::BFloat => rust_ty == cx.type_i16(),
1143 TypeKind::X86_AMX if cx.type_kind(rust_ty) == TypeKind::Vector => {
1144 let element_ty = cx.element_type(rust_ty);
1145 let element_count = cx.vector_length(rust_ty) as u64;
1146
1147 let element_size_bits = match cx.type_kind(element_ty) {
1148 TypeKind::Half => 16,
1149 TypeKind::Float => 32,
1150 TypeKind::Double => 64,
1151 TypeKind::FP128 => 128,
1152 TypeKind::Integer => cx.int_width(element_ty),
1153 TypeKind::Pointer => cx.int_width(cx.isize_ty),
1154 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("Vector element type `{0:?}` not one of integer, float or pointer",
element_ty))bug!(
1155 "Vector element type `{element_ty:?}` not one of integer, float or pointer"
1156 ),
1157 };
1158
1159 element_size_bits * element_count == 8192
1160 }
1161 _ => false,
1162 }
1163}
1164
1165fn autocast<'ll>(
1166 bx: &mut Builder<'_, 'll, '_>,
1167 val: &'ll Value,
1168 src_ty: &'ll Type,
1169 dest_ty: &'ll Type,
1170) -> &'ll Value {
1171 if src_ty == dest_ty {
1172 return val;
1173 }
1174 match (bx.type_kind(src_ty), bx.type_kind(dest_ty)) {
1175 (TypeKind::Struct, TypeKind::Struct) => {
1177 let mut ret = bx.const_poison(dest_ty);
1178 for (idx, (src_element_ty, dest_element_ty)) in
1179 iter::zip(bx.struct_element_types(src_ty), bx.struct_element_types(dest_ty))
1180 .enumerate()
1181 {
1182 let elt = bx.extract_value(val, idx as u64);
1183 let casted_elt = autocast(bx, elt, src_element_ty, dest_element_ty);
1184 ret = bx.insert_value(ret, casted_elt, idx as u64);
1185 }
1186 ret
1187 }
1188 (TypeKind::Vector, TypeKind::Integer) if bx.element_type(src_ty) == bx.type_i1() => {
1190 let vector_length = bx.vector_length(src_ty) as u64;
1191 let int_width = vector_length.next_power_of_two().max(8);
1192
1193 let val = if vector_length == int_width {
1194 val
1195 } else {
1196 let shuffle_indices = match vector_length {
1198 0 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("zero length vectors are not allowed")));
}unreachable!("zero length vectors are not allowed"),
1199 1 => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[0, 1, 1, 1, 1, 1, 1, 1]))vec![0, 1, 1, 1, 1, 1, 1, 1],
1200 2 => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[0, 1, 2, 2, 2, 2, 2, 2]))vec![0, 1, 2, 2, 2, 2, 2, 2],
1201 3 => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[0, 1, 2, 3, 3, 3, 3, 3]))vec![0, 1, 2, 3, 3, 3, 3, 3],
1202 4.. => (0..int_width as i32).collect(),
1203 };
1204 let shuffle_mask =
1205 shuffle_indices.into_iter().map(|i| bx.const_i32(i)).collect::<Vec<_>>();
1206 bx.shuffle_vector(val, bx.const_null(src_ty), bx.const_vector(&shuffle_mask))
1207 };
1208 bx.bitcast(val, dest_ty)
1209 }
1210 (TypeKind::Integer, TypeKind::Vector) if bx.element_type(dest_ty) == bx.type_i1() => {
1212 let vector_length = bx.vector_length(dest_ty) as u64;
1213 let int_width = vector_length.next_power_of_two().max(8);
1214
1215 let intermediate_ty = bx.type_vector(bx.type_i1(), int_width);
1216 let intermediate = bx.bitcast(val, intermediate_ty);
1217
1218 if vector_length == int_width {
1219 intermediate
1220 } else {
1221 let shuffle_mask: Vec<_> =
1222 (0..vector_length).map(|i| bx.const_i32(i as i32)).collect();
1223 bx.shuffle_vector(
1224 intermediate,
1225 bx.const_poison(intermediate_ty),
1226 bx.const_vector(&shuffle_mask),
1227 )
1228 }
1229 }
1230 (TypeKind::Vector, TypeKind::X86_AMX) => {
1231 bx.call_intrinsic("llvm.x86.cast.vector.to.tile", &[src_ty], &[val])
1232 }
1233 (TypeKind::X86_AMX, TypeKind::Vector) => {
1234 bx.call_intrinsic("llvm.x86.cast.tile.to.vector", &[dest_ty], &[val])
1235 }
1236 _ => bx.bitcast(val, dest_ty), }
1238}
1239
1240fn intrinsic_fn<'ll, 'tcx>(
1241 bx: &Builder<'_, 'll, 'tcx>,
1242 name: &str,
1243 rust_return_ty: &'ll Type,
1244 rust_argument_tys: Vec<&'ll Type>,
1245 instance: ty::Instance<'tcx>,
1246) -> &'ll Value {
1247 let tcx = bx.tcx;
1248
1249 let rust_fn_ty = bx.type_func(&rust_argument_tys, rust_return_ty);
1250
1251 let intrinsic = llvm::Intrinsic::lookup(name.as_bytes());
1252
1253 if let Some(intrinsic) = intrinsic
1254 && intrinsic.is_target_specific()
1255 {
1256 let (llvm_arch, _) = name[5..].split_once('.').unwrap();
1257 let rust_arch = &tcx.sess.target.arch;
1258
1259 if let Some(correct_llvm_arch) = llvm_arch_for(rust_arch)
1260 && llvm_arch != correct_llvm_arch
1261 {
1262 tcx.dcx().emit_fatal(IntrinsicWrongArch {
1263 name,
1264 target_arch: rust_arch.desc(),
1265 span: tcx.def_span(instance.def_id()),
1266 });
1267 }
1268 }
1269
1270 if let Some(intrinsic) = intrinsic
1271 && !intrinsic.is_overloaded()
1272 {
1273 let llfn = intrinsic.get_declaration(bx.llmod, &[]);
1275 let llvm_fn_ty = bx.get_type_of_global(llfn);
1276
1277 let llvm_return_ty = bx.get_return_type(llvm_fn_ty);
1278 let llvm_argument_tys = bx.func_params_types(llvm_fn_ty);
1279 let llvm_is_variadic = bx.func_is_variadic(llvm_fn_ty);
1280
1281 let is_correct_signature = !llvm_is_variadic
1282 && rust_argument_tys.len() == llvm_argument_tys.len()
1283 && iter::once((rust_return_ty, llvm_return_ty))
1284 .chain(iter::zip(rust_argument_tys, llvm_argument_tys))
1285 .all(|(rust_ty, llvm_ty)| can_autocast(bx, rust_ty, llvm_ty));
1286
1287 if !is_correct_signature {
1288 tcx.dcx().emit_fatal(IntrinsicSignatureMismatch {
1289 name,
1290 llvm_fn_ty: &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", llvm_fn_ty))
})format!("{llvm_fn_ty:?}"),
1291 rust_fn_ty: &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", rust_fn_ty))
})format!("{rust_fn_ty:?}"),
1292 span: tcx.def_span(instance.def_id()),
1293 });
1294 }
1295
1296 return llfn;
1297 }
1298
1299 let llfn = declare_raw_fn(
1301 bx,
1302 name,
1303 llvm::CCallConv,
1304 llvm::UnnamedAddr::Global,
1305 llvm::Visibility::Default,
1306 rust_fn_ty,
1307 );
1308
1309 if intrinsic.is_none() {
1310 let mut new_llfn = None;
1311 let can_upgrade = unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn) };
1312
1313 if !can_upgrade {
1314 tcx.dcx().emit_fatal(UnknownIntrinsic { name, span: tcx.def_span(instance.def_id()) });
1316 } else if let Some(def_id) = instance.def_id().as_local() {
1317 let hir_id = tcx.local_def_id_to_hir_id(def_id);
1319
1320 let msg = if let Some(new_llfn) = new_llfn {
1322 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("using deprecated intrinsic `{1}`, `{0}` can be used instead",
str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap(),
name))
})format!(
1323 "using deprecated intrinsic `{name}`, `{}` can be used instead",
1324 str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
1325 )
1326 } else {
1327 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("using deprecated intrinsic `{0}`",
name))
})format!("using deprecated intrinsic `{name}`")
1328 };
1329
1330 tcx.emit_node_lint(
1331 DEPRECATED_LLVM_INTRINSIC,
1332 hir_id,
1333 rustc_errors::DiagDecorator(|d| {
1334 d.primary_message(msg).span(tcx.hir_span(hir_id));
1335 }),
1336 );
1337 }
1338 }
1339
1340 llfn
1341}
1342
1343fn catch_unwind_intrinsic<'ll, 'tcx>(
1344 bx: &mut Builder<'_, 'll, 'tcx>,
1345 try_func: &'ll Value,
1346 data: &'ll Value,
1347 catch_func: &'ll Value,
1348) -> &'ll Value {
1349 if !bx.sess().panic_strategy().unwinds() {
1350 let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1351 bx.call(try_func_ty, None, None, try_func, &[data], None, None);
1352 bx.const_bool(false)
1355 } else if wants_msvc_seh(bx.sess()) {
1356 codegen_msvc_try(bx, try_func, data, catch_func)
1357 } else if wants_wasm_eh(bx.sess()) {
1358 codegen_wasm_try(bx, try_func, data, catch_func)
1359 } else {
1360 codegen_gnu_try(bx, try_func, data, catch_func)
1361 }
1362}
1363
1364fn codegen_msvc_try<'ll, 'tcx>(
1372 bx: &mut Builder<'_, 'll, 'tcx>,
1373 try_func: &'ll Value,
1374 data: &'ll Value,
1375 catch_func: &'ll Value,
1376) -> &'ll Value {
1377 let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
1378 bx.set_personality_fn(bx.eh_personality());
1379
1380 let normal = bx.append_sibling_block("normal");
1381 let catchswitch = bx.append_sibling_block("catchswitch");
1382 let catchpad_rust = bx.append_sibling_block("catchpad_rust");
1383 let catchpad_foreign = bx.append_sibling_block("catchpad_foreign");
1384 let caught = bx.append_sibling_block("caught");
1385
1386 let try_func = llvm::get_param(bx.llfn(), 0);
1387 let data = llvm::get_param(bx.llfn(), 1);
1388 let catch_func = llvm::get_param(bx.llfn(), 2);
1389
1390 let ptr_size = bx.tcx().data_layout.pointer_size();
1446 let ptr_align = bx.tcx().data_layout.pointer_align().abi;
1447 let slot = bx.alloca(ptr_size, ptr_align);
1448 let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1449 bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None);
1450
1451 bx.switch_to_block(normal);
1452 bx.ret(bx.const_bool(false));
1453
1454 bx.switch_to_block(catchswitch);
1455 let cs = bx.catch_switch(None, None, &[catchpad_rust, catchpad_foreign]);
1456
1457 let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_ptr());
1472 let type_name = bx.const_bytes(b"rust_panic\0");
1473 let type_info =
1474 bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false);
1475 let tydesc = bx.declare_global(
1476 &mangle_internal_symbol(bx.tcx, "__rust_panic_type_info"),
1477 bx.val_ty(type_info),
1478 );
1479
1480 llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
1481 if bx.cx.tcx.sess.target.supports_comdat() {
1482 llvm::SetUniqueComdat(bx.llmod, tydesc);
1483 }
1484 llvm::set_initializer(tydesc, type_info);
1485
1486 bx.switch_to_block(catchpad_rust);
1493 let flags = bx.const_i32(8);
1494 let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
1495 let ptr = bx.load(bx.type_ptr(), slot, ptr_align);
1496 let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
1497 bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None);
1498 bx.catch_ret(&funclet, caught);
1499
1500 bx.switch_to_block(catchpad_foreign);
1502 let flags = bx.const_i32(64);
1503 let null = bx.const_null(bx.type_ptr());
1504 let funclet = bx.catch_pad(cs, &[null, flags, null]);
1505 bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet), None);
1506 bx.catch_ret(&funclet, caught);
1507
1508 bx.switch_to_block(caught);
1509 bx.ret(bx.const_bool(true));
1510 });
1511
1512 let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
1515 ret
1516}
1517
1518fn codegen_wasm_try<'ll, 'tcx>(
1520 bx: &mut Builder<'_, 'll, 'tcx>,
1521 try_func: &'ll Value,
1522 data: &'ll Value,
1523 catch_func: &'ll Value,
1524) -> &'ll Value {
1525 let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
1526 bx.set_personality_fn(bx.eh_personality());
1527
1528 let normal = bx.append_sibling_block("normal");
1529 let catchswitch = bx.append_sibling_block("catchswitch");
1530 let catchpad = bx.append_sibling_block("catchpad");
1531 let caught = bx.append_sibling_block("caught");
1532
1533 let try_func = llvm::get_param(bx.llfn(), 0);
1534 let data = llvm::get_param(bx.llfn(), 1);
1535 let catch_func = llvm::get_param(bx.llfn(), 2);
1536
1537 let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1561 bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None);
1562
1563 bx.switch_to_block(normal);
1564 bx.ret(bx.const_bool(false));
1565
1566 bx.switch_to_block(catchswitch);
1567 let cs = bx.catch_switch(None, None, &[catchpad]);
1568
1569 bx.switch_to_block(catchpad);
1570 let null = bx.const_null(bx.type_ptr());
1571 let funclet = bx.catch_pad(cs, &[null]);
1572
1573 let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[], &[funclet.cleanuppad()]);
1574 let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[], &[funclet.cleanuppad()]);
1575
1576 let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
1577 bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None);
1578 bx.catch_ret(&funclet, caught);
1579
1580 bx.switch_to_block(caught);
1581 bx.ret(bx.const_bool(true));
1582 });
1583
1584 let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
1587 ret
1588}
1589
1590fn codegen_gnu_try<'ll, 'tcx>(
1602 bx: &mut Builder<'_, 'll, 'tcx>,
1603 try_func: &'ll Value,
1604 data: &'ll Value,
1605 catch_func: &'ll Value,
1606) -> &'ll Value {
1607 let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
1608 let then = bx.append_sibling_block("then");
1621 let catch = bx.append_sibling_block("catch");
1622
1623 let try_func = llvm::get_param(bx.llfn(), 0);
1624 let data = llvm::get_param(bx.llfn(), 1);
1625 let catch_func = llvm::get_param(bx.llfn(), 2);
1626 let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1627 bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None);
1628
1629 bx.switch_to_block(then);
1630 bx.ret(bx.const_bool(false));
1631
1632 bx.switch_to_block(catch);
1639 let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()], false);
1640 let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1);
1641 let tydesc = bx.const_null(bx.type_ptr());
1642 bx.add_clause(vals, tydesc);
1643 let ptr = bx.extract_value(vals, 0);
1644 let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
1645 bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None);
1646 bx.ret(bx.const_bool(true));
1647 });
1648
1649 let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
1652 ret
1653}
1654
1655fn gen_fn<'a, 'll, 'tcx>(
1658 cx: &'a CodegenCx<'ll, 'tcx>,
1659 name: &str,
1660 rust_fn_sig: ty::PolyFnSig<'tcx>,
1661 codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
1662) -> (&'ll Type, &'ll Value) {
1663 let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
1664 let llty = fn_abi.llvm_type(cx);
1665 let llfn = cx.declare_fn(name, fn_abi, None);
1666 cx.set_frame_pointer_type(llfn);
1667 cx.apply_target_cpu_attr(llfn);
1668 llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage);
1670 let llbb = Builder::append_block(cx, llfn, "entry-block");
1671 let bx = Builder::build(cx, llbb);
1672 codegen(bx);
1673 (llty, llfn)
1674}
1675
1676fn get_rust_try_fn<'a, 'll, 'tcx>(
1681 cx: &'a CodegenCx<'ll, 'tcx>,
1682 codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
1683) -> (&'ll Type, &'ll Value) {
1684 if let Some(llfn) = cx.rust_try_fn.get() {
1685 return llfn;
1686 }
1687
1688 let tcx = cx.tcx;
1690 let i8p = Ty::new_mut_ptr(tcx, tcx.types.i8);
1691 let try_fn_ty = Ty::new_fn_ptr(
1693 tcx,
1694 ty::Binder::dummy(tcx.mk_fn_sig_rust_abi([i8p], tcx.types.unit, hir::Safety::Unsafe)),
1695 );
1696 let catch_fn_ty = Ty::new_fn_ptr(
1698 tcx,
1699 ty::Binder::dummy(tcx.mk_fn_sig_rust_abi([i8p, i8p], tcx.types.unit, hir::Safety::Unsafe)),
1700 );
1701 let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig_rust_abi(
1703 [try_fn_ty, i8p, catch_fn_ty],
1704 tcx.types.bool,
1705 hir::Safety::Unsafe,
1706 ));
1707 let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
1708
1709 if cx.sess().pointer_authentication() {
1710 let cfg = cx.sess().pointer_auth_config.as_ref().unwrap();
1711 let attrs: Vec<&Attribute> =
1712 cfg.fn_attrs().into_iter().map(|name| llvm::CreateAttrString(cx.llcx, name)).collect();
1713
1714 let (_ty, rust_try_fn) = rust_try;
1715 crate::attributes::apply_to_llfn(rust_try_fn, AttributePlace::Function, &attrs);
1716 }
1717
1718 cx.rust_try_fn.set(Some(rust_try));
1719 rust_try
1720}
1721
1722fn codegen_retag_inner<'ll, 'tcx>(
1723 bx: &mut Builder<'_, 'll, 'tcx>,
1724 name: &'static str,
1725 ptr: &'ll Value,
1726 info: &RetagInfo<&'ll Value>,
1727) -> &'ll Value {
1728 let size = bx.const_usize(info.size.bytes());
1729 let perms = bx.const_u8(info.flags.bits());
1730
1731 bx.call_intrinsic(
1732 name,
1733 &[bx.type_ptr(), bx.val_ty(size), bx.type_i8(), bx.type_ptr(), bx.type_ptr()],
1736 &[ptr, size, perms, info.im_layout, info.pin_layout],
1737 )
1738}
1739
1740fn codegen_autodiff<'ll, 'tcx>(
1741 bx: &mut Builder<'_, 'll, 'tcx>,
1742 instance: ty::Instance<'tcx>,
1743 args: &[OperandRef<'tcx, &'ll Value>],
1744 result_layout: ty::layout::TyAndLayout<'tcx>,
1745 result_place: Option<PlaceValue<&'ll Value>>,
1746) -> IntrinsicResult<'tcx, &'ll Value> {
1747 let tcx = bx.tcx;
1748 if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) {
1749 let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutEnable);
1750 }
1751
1752 let ct = tcx.crate_types();
1753 let lto = tcx.sess.lto();
1754 if ct.len() == 1 && ct.contains(&CrateType::Executable) {
1755 if lto != rustc_session::config::Lto::Fat {
1756 let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutLto);
1757 }
1758 } else {
1759 if lto != rustc_session::config::Lto::Fat && !tcx.sess.opts.cg.linker_plugin_lto.enabled() {
1760 let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutLto);
1761 }
1762 }
1763
1764 let fn_args = instance.args;
1765 let callee_ty = instance.ty(tcx, bx.typing_env());
1766
1767 let sig = callee_ty.fn_sig(tcx).skip_binder();
1768
1769 let ret_ty = sig.output();
1770 let llret_ty = bx.layout_of(ret_ty).llvm_type(bx);
1771
1772 let source_fn_ptr_ty = fn_args.into_type_list(tcx)[0];
1773 let fn_to_diff = args[0].immediate();
1774
1775 let (diff_id, diff_args) = match fn_args.into_type_list(tcx)[1].kind() {
1776 ty::FnDef(def_id, diff_args) => (def_id, diff_args.no_bound_vars().unwrap()),
1777 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("invalid args"))bug!("invalid args"),
1778 };
1779
1780 let fn_diff = match Instance::try_resolve(tcx, bx.cx.typing_env(), *diff_id, diff_args) {
1781 Ok(Some(instance)) => instance,
1782 Ok(None) => ::rustc_middle::util::bug::bug_fmt(format_args!("could not resolve ({0:?}, {1:?}) to a specific autodiff instance",
diff_id, diff_args))bug!(
1783 "could not resolve ({:?}, {:?}) to a specific autodiff instance",
1784 diff_id,
1785 diff_args
1786 ),
1787 Err(err) => {
1788 return IntrinsicResult::Err(err);
1790 }
1791 };
1792
1793 let val_arr = get_args_from_tuple(bx, args[2], fn_diff);
1794 let diff_symbol = symbol_name_for_instance_in_crate(tcx, fn_diff.clone(), LOCAL_CRATE);
1795
1796 let Some(Some(mut diff_attrs)) =
1797 {
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(fn_diff.def_id(), &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcAutodiff(attr)) => {
break 'done Some(attr.clone());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, fn_diff.def_id(), RustcAutodiff(attr) => attr.clone())
1798 else {
1799 ::rustc_middle::util::bug::bug_fmt(format_args!("could not find autodiff attrs"))bug!("could not find autodiff attrs")
1800 };
1801
1802 adjust_activity_to_abi(
1803 tcx,
1804 source_fn_ptr_ty,
1805 TypingEnv::fully_monomorphized(),
1806 &mut diff_attrs.input_activity,
1807 );
1808
1809 let fnc_tree = fnc_typetrees(tcx, source_fn_ptr_ty);
1810
1811 generate_enzyme_call(
1813 bx,
1814 fn_to_diff,
1815 &diff_symbol,
1816 llret_ty,
1817 &val_arr,
1818 &diff_attrs,
1819 result_layout,
1820 result_place,
1821 fnc_tree,
1822 )
1823}
1824
1825fn codegen_offload<'ll, 'tcx>(
1830 bx: &mut Builder<'_, 'll, 'tcx>,
1831 tcx: TyCtxt<'tcx>,
1832 instance: ty::Instance<'tcx>,
1833 args: &[OperandRef<'tcx, &'ll Value>],
1834) {
1835 let cx = bx.cx;
1836 let fn_args = instance.args;
1837
1838 let (target_id, target_args) = match fn_args.into_type_list(tcx)[0].kind() {
1839 ty::FnDef(def_id, params) => (def_id, params.no_bound_vars().unwrap()),
1840 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("invalid offload intrinsic arg"))bug!("invalid offload intrinsic arg"),
1841 };
1842
1843 let fn_target = match Instance::try_resolve(tcx, cx.typing_env(), *target_id, target_args) {
1844 Ok(Some(instance)) => instance,
1845 Ok(None) => ::rustc_middle::util::bug::bug_fmt(format_args!("could not resolve ({0:?}, {1:?}) to a specific offload instance",
target_id, target_args))bug!(
1846 "could not resolve ({:?}, {:?}) to a specific offload instance",
1847 target_id,
1848 target_args
1849 ),
1850 Err(_) => {
1851 return;
1853 }
1854 };
1855
1856 let offload_dims = OffloadKernelDims::from_operands(bx, &args[1], &args[2]);
1857 let dyn_cache = match args[3].val {
1858 OperandValue::Immediate(val) => val,
1859 _ => { ::core::panicking::panic_fmt(format_args!("unparsable")); }panic!("unparsable"),
1860 };
1861 let device_id = match args[4].val {
1862 OperandValue::Immediate(val) => val,
1863 _ => { ::core::panicking::panic_fmt(format_args!("unparsable")); }panic!("unparsable"),
1864 };
1865 let args = get_args_from_tuple(bx, args[5], fn_target);
1866 let target_symbol = mangle_offload_export(tcx, fn_target);
1867
1868 let sig = tcx.fn_sig(fn_target.def_id()).instantiate(tcx, fn_target.args).skip_norm_wip();
1869 let sig = tcx.instantiate_bound_regions_with_erased(sig);
1870 let inputs = sig.inputs();
1871
1872 let fn_abi = cx.fn_abi_of_instance(fn_target, ty::List::empty());
1873
1874 let mut metadata = Vec::new();
1875 let mut types = Vec::new();
1876
1877 for (i, arg_abi) in fn_abi.args.iter().enumerate() {
1878 let ty = inputs[i];
1879 let decomposed = OffloadMetadata::handle_abi(cx, tcx, ty, arg_abi);
1880
1881 for (meta, entry_ty) in decomposed {
1882 metadata.push(meta);
1883 types.push(bx.cx.layout_of(entry_ty).llvm_type(bx.cx));
1884 }
1885 }
1886
1887 let offload_globals_ref = cx.offload_globals.borrow();
1888 let offload_globals = match offload_globals_ref.as_ref() {
1889 Some(globals) => globals,
1890 None => {
1891 return;
1893 }
1894 };
1895 register_offload(cx);
1896 let offload_data =
1897 gpu_offload::gen_define_handling(&cx, &metadata, target_symbol, offload_globals);
1898 gpu_offload::gen_call_handling(
1899 bx,
1900 &offload_data,
1901 &args,
1902 &types,
1903 &metadata,
1904 offload_globals,
1905 &offload_dims,
1906 &dyn_cache,
1907 &device_id,
1908 );
1909}
1910
1911fn get_args_from_tuple<'ll, 'tcx>(
1912 bx: &mut Builder<'_, 'll, 'tcx>,
1913 tuple_op: OperandRef<'tcx, &'ll Value>,
1914 fn_instance: Instance<'tcx>,
1915) -> Vec<&'ll Value> {
1916 let cx = bx.cx;
1917 let fn_abi = cx.fn_abi_of_instance(fn_instance, ty::List::empty());
1918
1919 match tuple_op.val {
1920 OperandValue::Immediate(val) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[val]))vec![val],
1921 OperandValue::Pair(v1, v2) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[v1, v2]))vec![v1, v2],
1922 OperandValue::Ref(ptr) => {
1923 let tuple_place = PlaceRef { val: ptr, layout: tuple_op.layout };
1924
1925 let mut result = Vec::with_capacity(fn_abi.args.len());
1926 let mut tuple_index = 0;
1927
1928 for arg in &fn_abi.args {
1929 match arg.mode {
1930 PassMode::Ignore => {}
1931 PassMode::Direct(_) | PassMode::Cast { .. } => {
1932 let field = tuple_place.project_field(bx, tuple_index);
1933 let llvm_ty = field.layout.llvm_type(bx.cx);
1934 let val = bx.load(llvm_ty, field.val.llval, field.val.align);
1935 result.push(val);
1936 tuple_index += 1;
1937 }
1938 PassMode::Pair(_, _) => {
1939 let field = tuple_place.project_field(bx, tuple_index);
1940 let llvm_ty = field.layout.llvm_type(bx.cx);
1941 let pair_val = bx.load(llvm_ty, field.val.llval, field.val.align);
1942 result.push(bx.extract_value(pair_val, 0));
1943 result.push(bx.extract_value(pair_val, 1));
1944 tuple_index += 1;
1945 }
1946 PassMode::Indirect { .. } => {
1947 let field = tuple_place.project_field(bx, tuple_index);
1948 result.push(field.val.llval);
1949 tuple_index += 1;
1950 }
1951 }
1952 }
1953
1954 result
1955 }
1956
1957 OperandValue::ZeroSized => ::alloc::vec::Vec::new()vec![],
1958 }
1959}
1960
1961fn generic_simd_intrinsic<'ll, 'tcx>(
1962 bx: &mut Builder<'_, 'll, 'tcx>,
1963 name: Symbol,
1964 fn_args: GenericArgsRef<'tcx>,
1965 args: &[OperandRef<'tcx, &'ll Value>],
1966 ret_ty: Ty<'tcx>,
1967 llret_ty: &'ll Type,
1968 span: Span,
1969) -> Result<&'ll Value, ErrorGuaranteed> {
1970 macro_rules! return_error {
1971 ($diag: expr) => {{
1972 let err = bx.sess().dcx().emit_err($diag);
1973 return Err(err);
1974 }};
1975 }
1976
1977 macro_rules! require {
1978 ($cond: expr, $diag: expr) => {
1979 if !$cond {
1980 return_error!($diag);
1981 }
1982 };
1983 }
1984
1985 macro_rules! require_simd {
1986 ($ty: expr, $variant:ident) => {{
1987 require!($ty.is_simd(), InvalidMonomorphization::$variant { span, name, ty: $ty });
1988 $ty.simd_size_and_type(bx.tcx())
1989 }};
1990 }
1991
1992 macro_rules! require_simd_or_scalable {
1993 ($ty: expr, $variant:ident) => {{
1994 require!(
1995 $ty.is_simd() || $ty.is_scalable_vector(),
1996 InvalidMonomorphization::$variant { span, name, ty: $ty }
1997 );
1998 if $ty.is_simd() {
1999 let (len, ty) = $ty.simd_size_and_type(bx.tcx());
2000 (len, ty, None)
2001 } else {
2002 let (count, ty, num_vecs) =
2003 $ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
2004 (count as u64, ty, Some(num_vecs))
2005 }
2006 }};
2007 }
2008
2009 macro_rules! require_int_or_uint_ty {
2011 ($ty: expr, $diag: expr) => {
2012 match $ty {
2013 ty::Int(i) => {
2014 i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
2015 }
2016 ty::Uint(i) => {
2017 i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
2018 }
2019 _ => {
2020 return_error!($diag);
2021 }
2022 }
2023 };
2024 }
2025
2026 let llvm_version = crate::llvm_util::get_version();
2027
2028 fn vector_mask_to_bitmask<'a, 'll, 'tcx>(
2042 bx: &mut Builder<'a, 'll, 'tcx>,
2043 i_xn: &'ll Value,
2044 in_elem_bitwidth: u64,
2045 in_len: u64,
2046 ) -> &'ll Value {
2047 let shift_idx = bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _);
2049 let shift_indices = ::alloc::vec::from_elem(shift_idx, in_len as _)vec![shift_idx; in_len as _];
2050 let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice()));
2051 bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len))
2053 }
2054
2055 if truecfg!(debug_assertions) {
2057 for arg in args {
2058 if arg.layout.ty.is_simd() {
2059 {
match arg.val {
OperandValue::Immediate(_) => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"OperandValue::Immediate(_)", ::core::option::Option::None);
}
}
};assert_matches!(arg.val, OperandValue::Immediate(_));
2060 }
2061 }
2062 }
2063
2064 if name == sym::simd_select_bitmask {
2065 let (len, _) = {
if !args[1].layout.ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdArgument {
span,
name,
ty: args[1].layout.ty,
});
return Err(err);
};
};
args[1].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[1].layout.ty, SimdArgument);
2066
2067 let expected_int_bits = len.max(8).next_power_of_two();
2068 let expected_bytes = len.div_ceil(8);
2069
2070 let mask_ty = args[0].layout.ty;
2071 let mask = match mask_ty.kind() {
2072 ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
2073 ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
2074 ty::Array(elem, len)
2075 if #[allow(non_exhaustive_omitted_patterns)] match elem.kind() {
ty::Uint(ty::UintTy::U8) => true,
_ => false,
}matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
2076 && len
2077 .try_to_target_usize(bx.tcx)
2078 .expect("expected monomorphic const in codegen")
2079 == expected_bytes =>
2080 {
2081 let place = PlaceRef::alloca(bx, args[0].layout);
2082 args[0].val.store(bx, place);
2083 let int_ty = bx.type_ix(expected_bytes * 8);
2084 bx.load(int_ty, place.val.llval, Align::ONE)
2085 }
2086 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::InvalidBitmask {
span,
name,
mask_ty,
expected_int_bits,
expected_bytes,
});
return Err(err);
}return_error!(InvalidMonomorphization::InvalidBitmask {
2087 span,
2088 name,
2089 mask_ty,
2090 expected_int_bits,
2091 expected_bytes
2092 }),
2093 };
2094
2095 let i1 = bx.type_i1();
2096 let im = bx.type_ix(len);
2097 let i1xn = bx.type_vector(i1, len);
2098 let m_im = bx.trunc(mask, im);
2099 let m_i1s = bx.bitcast(m_im, i1xn);
2100 return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
2101 }
2102
2103 if name == sym::simd_splat {
2104 let (out_len, out_ty) = {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2105
2106 if !(args[0].layout.ty == out_ty) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedVectorElementType {
span,
name,
expected_element: out_ty,
vector_type: ret_ty,
});
return Err(err);
};
};require!(
2107 args[0].layout.ty == out_ty,
2108 InvalidMonomorphization::ExpectedVectorElementType {
2109 span,
2110 name,
2111 expected_element: out_ty,
2112 vector_type: ret_ty,
2113 }
2114 );
2115
2116 let poison_vec = bx.const_poison(llret_ty);
2118 let idx0 = bx.const_i32(0);
2119 let v0 = bx.insert_element(poison_vec, args[0].immediate(), idx0);
2120
2121 let mask_ty = bx.type_vector(bx.type_i32(), out_len);
2124 let splat = bx.shuffle_vector(v0, poison_vec, bx.const_null(mask_ty));
2125
2126 return Ok(splat);
2127 }
2128
2129 let supports_scalable = match name {
2130 sym::simd_cast | sym::simd_select => true,
2131 _ => false,
2132 };
2133
2134 if !supports_scalable {
2139 let _ = {
if !args[0].layout.ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdInput {
span,
name,
ty: args[0].layout.ty,
});
return Err(err);
};
};
args[0].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[0].layout.ty, SimdInput);
2140 }
2141 let (in_len, in_elem, in_num_vecs) = {
if !(args[0].layout.ty.is_simd() ||
args[0].layout.ty.is_scalable_vector()) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdInput {
span,
name,
ty: args[0].layout.ty,
});
return Err(err);
};
};
if args[0].layout.ty.is_simd() {
let (len, ty) = args[0].layout.ty.simd_size_and_type(bx.tcx());
(len, ty, None)
} else {
let (count, ty, num_vecs) =
args[0].layout.ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
(count as u64, ty, Some(num_vecs))
}
}require_simd_or_scalable!(args[0].layout.ty, SimdInput);
2142 let in_ty = args[0].layout.ty;
2143
2144 let comparison = match name {
2145 sym::simd_eq => Some(BinOp::Eq),
2146 sym::simd_ne => Some(BinOp::Ne),
2147 sym::simd_lt => Some(BinOp::Lt),
2148 sym::simd_le => Some(BinOp::Le),
2149 sym::simd_gt => Some(BinOp::Gt),
2150 sym::simd_ge => Some(BinOp::Ge),
2151 _ => None,
2152 };
2153
2154 if let Some(cmp_op) = comparison {
2155 let (out_len, out_ty) = {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2156
2157 if !(in_len == out_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
span,
name,
in_len,
in_ty,
ret_ty,
out_len,
});
return Err(err);
};
};require!(
2158 in_len == out_len,
2159 InvalidMonomorphization::ReturnLengthInputType {
2160 span,
2161 name,
2162 in_len,
2163 in_ty,
2164 ret_ty,
2165 out_len
2166 }
2167 );
2168 if !(bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnIntegerType {
span,
name,
ret_ty,
out_ty,
});
return Err(err);
};
};require!(
2169 bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
2170 InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty }
2171 );
2172
2173 return Ok(compare_simd_types(
2174 bx,
2175 args[0].immediate(),
2176 args[1].immediate(),
2177 in_elem,
2178 llret_ty,
2179 cmp_op,
2180 ));
2181 }
2182
2183 if name == sym::simd_shuffle_const_generic {
2184 let idx = fn_args[2].expect_const().to_branch();
2185 let n = idx.len() as u64;
2186
2187 let (out_len, out_ty) = {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2188 if !(out_len == n) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLength {
span,
name,
in_len: n,
ret_ty,
out_len,
});
return Err(err);
};
};require!(
2189 out_len == n,
2190 InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
2191 );
2192 if !(in_elem == out_ty) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnElement {
span,
name,
in_elem,
in_ty,
ret_ty,
out_ty,
});
return Err(err);
};
};require!(
2193 in_elem == out_ty,
2194 InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
2195 );
2196
2197 let total_len = in_len * 2;
2198
2199 let indices: Option<Vec<_>> = idx
2200 .iter()
2201 .enumerate()
2202 .map(|(arg_idx, val)| {
2203 let idx = val.to_leaf().to_i32();
2204 if idx >= i32::try_from(total_len).unwrap() {
2205 bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
2206 span,
2207 name,
2208 arg_idx: arg_idx as u64,
2209 total_len: total_len.into(),
2210 });
2211 None
2212 } else {
2213 Some(bx.const_i32(idx))
2214 }
2215 })
2216 .collect();
2217 let Some(indices) = indices else {
2218 return Ok(bx.const_null(llret_ty));
2219 };
2220
2221 return Ok(bx.shuffle_vector(
2222 args[0].immediate(),
2223 args[1].immediate(),
2224 bx.const_vector(&indices),
2225 ));
2226 }
2227
2228 if name == sym::simd_shuffle {
2229 let idx_ty = args[2].layout.ty;
2231 let n: u64 = if idx_ty.is_simd()
2232 && #[allow(non_exhaustive_omitted_patterns)] match idx_ty.simd_size_and_type(bx.cx.tcx).1.kind()
{
ty::Uint(ty::UintTy::U32) => true,
_ => false,
}matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
2233 {
2234 idx_ty.simd_size_and_type(bx.cx.tcx).0
2235 } else {
2236 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdShuffle {
span,
name,
ty: idx_ty,
});
return Err(err);
}return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty })
2237 };
2238
2239 let (out_len, out_ty) = {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2240 if !(out_len == n) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLength {
span,
name,
in_len: n,
ret_ty,
out_len,
});
return Err(err);
};
};require!(
2241 out_len == n,
2242 InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
2243 );
2244 if !(in_elem == out_ty) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnElement {
span,
name,
in_elem,
in_ty,
ret_ty,
out_ty,
});
return Err(err);
};
};require!(
2245 in_elem == out_ty,
2246 InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
2247 );
2248
2249 let total_len = u128::from(in_len) * 2;
2250
2251 let indices = args[2].immediate();
2253 for i in 0..n {
2254 let val = bx.const_get_elt(indices, i as u64);
2255 let idx = bx
2256 .const_to_opt_u128(val, true)
2257 .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("typeck should have already ensured that these are const"))bug!("typeck should have already ensured that these are const"));
2258 if idx >= total_len {
2259 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
span,
name,
arg_idx: i,
total_len,
});
return Err(err);
};return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
2260 span,
2261 name,
2262 arg_idx: i,
2263 total_len,
2264 });
2265 }
2266 }
2267
2268 return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), indices));
2269 }
2270
2271 if name == sym::simd_insert || name == sym::simd_insert_dyn {
2272 if !(in_elem == args[2].layout.ty) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::InsertedType {
span,
name,
in_elem,
in_ty,
out_ty: args[2].layout.ty,
});
return Err(err);
};
};require!(
2273 in_elem == args[2].layout.ty,
2274 InvalidMonomorphization::InsertedType {
2275 span,
2276 name,
2277 in_elem,
2278 in_ty,
2279 out_ty: args[2].layout.ty
2280 }
2281 );
2282
2283 let index_imm = if name == sym::simd_insert {
2284 let idx = bx
2285 .const_to_opt_u128(args[1].immediate(), false)
2286 .expect("typeck should have ensure that this is a const");
2287 if idx >= in_len.into() {
2288 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
span,
name,
arg_idx: 1,
total_len: in_len.into(),
});
return Err(err);
};return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
2289 span,
2290 name,
2291 arg_idx: 1,
2292 total_len: in_len.into(),
2293 });
2294 }
2295 bx.const_i32(idx as i32)
2296 } else {
2297 args[1].immediate()
2298 };
2299
2300 return Ok(bx.insert_element(args[0].immediate(), args[2].immediate(), index_imm));
2301 }
2302 if name == sym::simd_extract || name == sym::simd_extract_dyn {
2303 if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};require!(
2304 ret_ty == in_elem,
2305 InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
2306 );
2307 let index_imm = if name == sym::simd_extract {
2308 let idx = bx
2309 .const_to_opt_u128(args[1].immediate(), false)
2310 .expect("typeck should have ensure that this is a const");
2311 if idx >= in_len.into() {
2312 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
span,
name,
arg_idx: 1,
total_len: in_len.into(),
});
return Err(err);
};return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
2313 span,
2314 name,
2315 arg_idx: 1,
2316 total_len: in_len.into(),
2317 });
2318 }
2319 bx.const_i32(idx as i32)
2320 } else {
2321 args[1].immediate()
2322 };
2323
2324 return Ok(bx.extract_element(args[0].immediate(), index_imm));
2325 }
2326
2327 if name == sym::simd_select {
2328 let m_elem_ty = in_elem;
2329 let m_len = in_len;
2330 let (v_len, _, _) = {
if !(args[1].layout.ty.is_simd() ||
args[1].layout.ty.is_scalable_vector()) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdArgument {
span,
name,
ty: args[1].layout.ty,
});
return Err(err);
};
};
if args[1].layout.ty.is_simd() {
let (len, ty) = args[1].layout.ty.simd_size_and_type(bx.tcx());
(len, ty, None)
} else {
let (count, ty, num_vecs) =
args[1].layout.ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
(count as u64, ty, Some(num_vecs))
}
}require_simd_or_scalable!(args[1].layout.ty, SimdArgument);
2331 if !(m_len == v_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MismatchedLengths {
span,
name,
m_len,
v_len,
});
return Err(err);
};
};require!(
2332 m_len == v_len,
2333 InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
2334 );
2335
2336 let m_i1s = if args[1].layout.ty.is_scalable_vector() {
2337 match m_elem_ty.kind() {
2338 ty::Bool => {}
2339 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: m_elem_ty,
});
return Err(err);
}return_error!(InvalidMonomorphization::MaskWrongElementType {
2340 span,
2341 name,
2342 ty: m_elem_ty
2343 }),
2344 };
2345 let i1 = bx.type_i1();
2346 let i1xn = bx.type_scalable_vector(i1, m_len as u64);
2347 bx.trunc(args[0].immediate(), i1xn)
2348 } else {
2349 let in_elem_bitwidth = match m_elem_ty.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: m_elem_ty,
});
return Err(err);
};
}
}require_int_or_uint_ty!(
2350 m_elem_ty.kind(),
2351 InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
2352 );
2353 vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len)
2354 };
2355
2356 return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
2357 }
2358
2359 if name == sym::simd_bitmask {
2360 let expected_int_bits = in_len.max(8).next_power_of_two();
2369 let expected_bytes = in_len.div_ceil(8);
2370
2371 let in_elem_bitwidth = match in_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: in_elem,
});
return Err(err);
};
}
}require_int_or_uint_ty!(
2373 in_elem.kind(),
2374 InvalidMonomorphization::MaskWrongElementType { span, name, ty: in_elem }
2375 );
2376
2377 let i1xn = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, in_len);
2378 let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
2380
2381 match ret_ty.kind() {
2382 ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
2383 return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
2385 }
2386 ty::Array(elem, len)
2387 if #[allow(non_exhaustive_omitted_patterns)] match elem.kind() {
ty::Uint(ty::UintTy::U8) => true,
_ => false,
}matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
2388 && len
2389 .try_to_target_usize(bx.tcx)
2390 .expect("expected monomorphic const in codegen")
2391 == expected_bytes =>
2392 {
2393 let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
2395
2396 let ptr = bx.alloca(Size::from_bytes(expected_bytes), Align::ONE);
2398 bx.store(ze, ptr, Align::ONE);
2399 let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
2400 return Ok(bx.load(array_ty, ptr, Align::ONE));
2401 }
2402 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::CannotReturn {
span,
name,
ret_ty,
expected_int_bits,
expected_bytes,
});
return Err(err);
}return_error!(InvalidMonomorphization::CannotReturn {
2403 span,
2404 name,
2405 ret_ty,
2406 expected_int_bits,
2407 expected_bytes
2408 }),
2409 }
2410 }
2411
2412 fn simd_simple_float_intrinsic<'ll, 'tcx>(
2413 name: Symbol,
2414 in_elem: Ty<'_>,
2415 in_ty: Ty<'_>,
2416 in_len: u64,
2417 bx: &mut Builder<'_, 'll, 'tcx>,
2418 span: Span,
2419 args: &[OperandRef<'tcx, &'ll Value>],
2420 ) -> Result<&'ll Value, ErrorGuaranteed> {
2421 macro_rules! return_error {
2422 ($diag: expr) => {{
2423 let err = bx.sess().dcx().emit_err($diag);
2424 return Err(err);
2425 }};
2426 }
2427
2428 let ty::Float(f) = in_elem.kind() else {
2429 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
span,
name,
ty: in_ty,
});
return Err(err);
};return_error!(InvalidMonomorphization::BasicFloatType { span, name, ty: in_ty });
2430 };
2431 let elem_ty = bx.cx.type_float_from_ty(*f);
2432
2433 let vec_ty = bx.type_vector(elem_ty, in_len);
2434
2435 let intr_name = match name {
2436 sym::simd_ceil => "llvm.ceil",
2437 sym::simd_fabs => "llvm.fabs",
2438 sym::simd_fcos => "llvm.cos",
2439 sym::simd_fexp2 => "llvm.exp2",
2440 sym::simd_fexp => "llvm.exp",
2441 sym::simd_flog10 => "llvm.log10",
2442 sym::simd_flog2 => "llvm.log2",
2443 sym::simd_flog => "llvm.log",
2444 sym::simd_floor => "llvm.floor",
2445 sym::simd_fma => "llvm.fma",
2446 sym::simd_relaxed_fma => "llvm.fmuladd",
2447 sym::simd_fsin => "llvm.sin",
2448 sym::simd_fsqrt => "llvm.sqrt",
2449 sym::simd_round => "llvm.round",
2450 sym::simd_round_ties_even => "llvm.rint",
2451 sym::simd_trunc => "llvm.trunc",
2452 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnrecognizedIntrinsic {
span,
name,
});
return Err(err);
}return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
2453 };
2454 Ok(bx.call_intrinsic(
2455 intr_name,
2456 &[vec_ty],
2457 &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
2458 ))
2459 }
2460
2461 if #[allow(non_exhaustive_omitted_patterns)] match name {
sym::simd_ceil | sym::simd_fabs | sym::simd_fcos | sym::simd_fexp2 |
sym::simd_fexp | sym::simd_flog10 | sym::simd_flog2 | sym::simd_flog |
sym::simd_floor | sym::simd_fma | sym::simd_fsin | sym::simd_fsqrt |
sym::simd_relaxed_fma | sym::simd_round | sym::simd_round_ties_even |
sym::simd_trunc => true,
_ => false,
}std::matches!(
2462 name,
2463 sym::simd_ceil
2464 | sym::simd_fabs
2465 | sym::simd_fcos
2466 | sym::simd_fexp2
2467 | sym::simd_fexp
2468 | sym::simd_flog10
2469 | sym::simd_flog2
2470 | sym::simd_flog
2471 | sym::simd_floor
2472 | sym::simd_fma
2473 | sym::simd_fsin
2474 | sym::simd_fsqrt
2475 | sym::simd_relaxed_fma
2476 | sym::simd_round
2477 | sym::simd_round_ties_even
2478 | sym::simd_trunc
2479 ) {
2480 return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
2481 }
2482
2483 fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -> &'ll Type {
2484 let elem_ty = match *elem_ty.kind() {
2485 ty::Int(v) => cx.type_int_from_ty(v),
2486 ty::Uint(v) => cx.type_uint_from_ty(v),
2487 ty::Float(v) => cx.type_float_from_ty(v),
2488 ty::RawPtr(_, _) => cx.type_ptr(),
2489 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
2490 };
2491 cx.type_vector(elem_ty, vec_len)
2492 }
2493
2494 if name == sym::simd_gather {
2495 let (_, element_ty0) = {
if !in_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdFirst {
span,
name,
ty: in_ty,
});
return Err(err);
};
};
in_ty.simd_size_and_type(bx.tcx())
}require_simd!(in_ty, SimdFirst);
2506 let (out_len, element_ty1) = {
if !args[1].layout.ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdSecond {
span,
name,
ty: args[1].layout.ty,
});
return Err(err);
};
};
args[1].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[1].layout.ty, SimdSecond);
2507 let (out_len2, element_ty2) = {
if !args[2].layout.ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
span,
name,
ty: args[2].layout.ty,
});
return Err(err);
};
};
args[2].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[2].layout.ty, SimdThird);
2509 {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
};require_simd!(ret_ty, SimdReturn);
2510
2511 if !(in_len == out_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SecondArgumentLength {
span,
name,
in_len,
in_ty,
arg_ty: args[1].layout.ty,
out_len,
});
return Err(err);
};
};require!(
2513 in_len == out_len,
2514 InvalidMonomorphization::SecondArgumentLength {
2515 span,
2516 name,
2517 in_len,
2518 in_ty,
2519 arg_ty: args[1].layout.ty,
2520 out_len
2521 }
2522 );
2523 if !(in_len == out_len2) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
span,
name,
in_len,
in_ty,
arg_ty: args[2].layout.ty,
out_len: out_len2,
});
return Err(err);
};
};require!(
2524 in_len == out_len2,
2525 InvalidMonomorphization::ThirdArgumentLength {
2526 span,
2527 name,
2528 in_len,
2529 in_ty,
2530 arg_ty: args[2].layout.ty,
2531 out_len: out_len2
2532 }
2533 );
2534
2535 if !(ret_ty == in_ty) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedReturnType {
span,
name,
in_ty,
ret_ty,
});
return Err(err);
};
};require!(
2537 ret_ty == in_ty,
2538 InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
2539 );
2540
2541 if !#[allow(non_exhaustive_omitted_patterns)] match *element_ty1.kind() {
ty::RawPtr(p_ty, _) if
p_ty == in_elem && p_ty.kind() == element_ty0.kind() => true,
_ => false,
} {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
span,
name,
expected_element: element_ty1,
second_arg: args[1].layout.ty,
in_elem,
in_ty,
mutability: ExpectedPointerMutability::Not,
});
return Err(err);
};
};require!(
2542 matches!(
2543 *element_ty1.kind(),
2544 ty::RawPtr(p_ty, _) if p_ty == in_elem && p_ty.kind() == element_ty0.kind()
2545 ),
2546 InvalidMonomorphization::ExpectedElementType {
2547 span,
2548 name,
2549 expected_element: element_ty1,
2550 second_arg: args[1].layout.ty,
2551 in_elem,
2552 in_ty,
2553 mutability: ExpectedPointerMutability::Not,
2554 }
2555 );
2556
2557 let mask_elem_bitwidth = match element_ty2.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: element_ty2,
});
return Err(err);
};
}
}require_int_or_uint_ty!(
2558 element_ty2.kind(),
2559 InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
2560 );
2561
2562 let alignment = bx.align_of(in_elem).bytes();
2564
2565 let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
2567
2568 let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
2570
2571 let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
2573
2574 let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2575 let alignment = bx.const_i32(alignment as i32);
2576 &[args[1].immediate(), alignment, mask, args[0].immediate()]
2577 } else {
2578 &[args[1].immediate(), mask, args[0].immediate()]
2579 };
2580
2581 let call =
2582 bx.call_intrinsic("llvm.masked.gather", &[llvm_elem_vec_ty, llvm_pointer_vec_ty], args);
2583 if llvm_version >= (22, 0, 0) {
2584 crate::attributes::apply_to_callsite(
2585 call,
2586 crate::llvm::AttributePlace::Argument(0),
2587 &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2588 )
2589 }
2590 return Ok(call);
2591 }
2592
2593 fn llvm_alignment<'ll, 'tcx>(
2594 bx: &mut Builder<'_, 'll, 'tcx>,
2595 alignment: SimdAlign,
2596 vector_ty: Ty<'tcx>,
2597 element_ty: Ty<'tcx>,
2598 ) -> u64 {
2599 match alignment {
2600 SimdAlign::Unaligned => 1,
2601 SimdAlign::Element => bx.align_of(element_ty).bytes(),
2602 SimdAlign::Vector => bx.align_of(vector_ty).bytes(),
2603 }
2604 }
2605
2606 if name == sym::simd_masked_load {
2607 let alignment = fn_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment();
2616
2617 let mask_ty = in_ty;
2619 let (mask_len, mask_elem) = (in_len, in_elem);
2620
2621 let pointer_ty = args[1].layout.ty;
2623
2624 let values_ty = args[2].layout.ty;
2626 let (values_len, values_elem) = {
if !values_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
span,
name,
ty: values_ty,
});
return Err(err);
};
};
values_ty.simd_size_and_type(bx.tcx())
}require_simd!(values_ty, SimdThird);
2627
2628 {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
};require_simd!(ret_ty, SimdReturn);
2629
2630 if !(values_len == mask_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
span,
name,
in_len: mask_len,
in_ty: mask_ty,
arg_ty: values_ty,
out_len: values_len,
});
return Err(err);
};
};require!(
2632 values_len == mask_len,
2633 InvalidMonomorphization::ThirdArgumentLength {
2634 span,
2635 name,
2636 in_len: mask_len,
2637 in_ty: mask_ty,
2638 arg_ty: values_ty,
2639 out_len: values_len
2640 }
2641 );
2642
2643 if !(ret_ty == values_ty) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedReturnType {
span,
name,
in_ty: values_ty,
ret_ty,
});
return Err(err);
};
};require!(
2645 ret_ty == values_ty,
2646 InvalidMonomorphization::ExpectedReturnType { span, name, in_ty: values_ty, ret_ty }
2647 );
2648
2649 if !#[allow(non_exhaustive_omitted_patterns)] match *pointer_ty.kind() {
ty::RawPtr(p_ty, _) if
p_ty == values_elem && p_ty.kind() == values_elem.kind() =>
true,
_ => false,
} {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
span,
name,
expected_element: values_elem,
second_arg: pointer_ty,
in_elem: values_elem,
in_ty: values_ty,
mutability: ExpectedPointerMutability::Not,
});
return Err(err);
};
};require!(
2650 matches!(
2651 *pointer_ty.kind(),
2652 ty::RawPtr(p_ty, _) if p_ty == values_elem && p_ty.kind() == values_elem.kind()
2653 ),
2654 InvalidMonomorphization::ExpectedElementType {
2655 span,
2656 name,
2657 expected_element: values_elem,
2658 second_arg: pointer_ty,
2659 in_elem: values_elem,
2660 in_ty: values_ty,
2661 mutability: ExpectedPointerMutability::Not,
2662 }
2663 );
2664
2665 let m_elem_bitwidth = match mask_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: mask_elem,
});
return Err(err);
};
}
}require_int_or_uint_ty!(
2666 mask_elem.kind(),
2667 InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
2668 );
2669
2670 let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
2671
2672 let alignment = llvm_alignment(bx, alignment, values_ty, values_elem);
2674
2675 let llvm_pointer = bx.type_ptr();
2676
2677 let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
2679
2680 let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2681 let alignment = bx.const_i32(alignment as i32);
2682
2683 &[args[1].immediate(), alignment, mask, args[2].immediate()]
2684 } else {
2685 &[args[1].immediate(), mask, args[2].immediate()]
2686 };
2687
2688 let call = bx.call_intrinsic("llvm.masked.load", &[llvm_elem_vec_ty, llvm_pointer], args);
2689 if llvm_version >= (22, 0, 0) {
2690 crate::attributes::apply_to_callsite(
2691 call,
2692 crate::llvm::AttributePlace::Argument(0),
2693 &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2694 )
2695 }
2696 return Ok(call);
2697 }
2698
2699 if name == sym::simd_masked_store {
2700 let alignment = fn_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment();
2709
2710 let mask_ty = in_ty;
2712 let (mask_len, mask_elem) = (in_len, in_elem);
2713
2714 let pointer_ty = args[1].layout.ty;
2716
2717 let values_ty = args[2].layout.ty;
2719 let (values_len, values_elem) = {
if !values_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
span,
name,
ty: values_ty,
});
return Err(err);
};
};
values_ty.simd_size_and_type(bx.tcx())
}require_simd!(values_ty, SimdThird);
2720
2721 if !(values_len == mask_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
span,
name,
in_len: mask_len,
in_ty: mask_ty,
arg_ty: values_ty,
out_len: values_len,
});
return Err(err);
};
};require!(
2723 values_len == mask_len,
2724 InvalidMonomorphization::ThirdArgumentLength {
2725 span,
2726 name,
2727 in_len: mask_len,
2728 in_ty: mask_ty,
2729 arg_ty: values_ty,
2730 out_len: values_len
2731 }
2732 );
2733
2734 if !#[allow(non_exhaustive_omitted_patterns)] match *pointer_ty.kind() {
ty::RawPtr(p_ty, p_mutbl) if
p_ty == values_elem && p_ty.kind() == values_elem.kind() &&
p_mutbl.is_mut() => true,
_ => false,
} {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
span,
name,
expected_element: values_elem,
second_arg: pointer_ty,
in_elem: values_elem,
in_ty: values_ty,
mutability: ExpectedPointerMutability::Mut,
});
return Err(err);
};
};require!(
2736 matches!(
2737 *pointer_ty.kind(),
2738 ty::RawPtr(p_ty, p_mutbl)
2739 if p_ty == values_elem && p_ty.kind() == values_elem.kind() && p_mutbl.is_mut()
2740 ),
2741 InvalidMonomorphization::ExpectedElementType {
2742 span,
2743 name,
2744 expected_element: values_elem,
2745 second_arg: pointer_ty,
2746 in_elem: values_elem,
2747 in_ty: values_ty,
2748 mutability: ExpectedPointerMutability::Mut,
2749 }
2750 );
2751
2752 let m_elem_bitwidth = match mask_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: mask_elem,
});
return Err(err);
};
}
}require_int_or_uint_ty!(
2753 mask_elem.kind(),
2754 InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
2755 );
2756
2757 let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
2758
2759 let alignment = llvm_alignment(bx, alignment, values_ty, values_elem);
2761
2762 let llvm_pointer = bx.type_ptr();
2763
2764 let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
2766
2767 let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2768 let alignment = bx.const_i32(alignment as i32);
2769 &[args[2].immediate(), args[1].immediate(), alignment, mask]
2770 } else {
2771 &[args[2].immediate(), args[1].immediate(), mask]
2772 };
2773
2774 let call = bx.call_intrinsic("llvm.masked.store", &[llvm_elem_vec_ty, llvm_pointer], args);
2775 if llvm_version >= (22, 0, 0) {
2776 crate::attributes::apply_to_callsite(
2777 call,
2778 crate::llvm::AttributePlace::Argument(1),
2779 &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2780 )
2781 }
2782 return Ok(call);
2783 }
2784
2785 if name == sym::simd_scatter {
2786 let (_, element_ty0) = {
if !in_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdFirst {
span,
name,
ty: in_ty,
});
return Err(err);
};
};
in_ty.simd_size_and_type(bx.tcx())
}require_simd!(in_ty, SimdFirst);
2796 let (element_len1, element_ty1) = {
if !args[1].layout.ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdSecond {
span,
name,
ty: args[1].layout.ty,
});
return Err(err);
};
};
args[1].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[1].layout.ty, SimdSecond);
2797 let (element_len2, element_ty2) = {
if !args[2].layout.ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
span,
name,
ty: args[2].layout.ty,
});
return Err(err);
};
};
args[2].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[2].layout.ty, SimdThird);
2798
2799 if !(in_len == element_len1) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SecondArgumentLength {
span,
name,
in_len,
in_ty,
arg_ty: args[1].layout.ty,
out_len: element_len1,
});
return Err(err);
};
};require!(
2801 in_len == element_len1,
2802 InvalidMonomorphization::SecondArgumentLength {
2803 span,
2804 name,
2805 in_len,
2806 in_ty,
2807 arg_ty: args[1].layout.ty,
2808 out_len: element_len1
2809 }
2810 );
2811 if !(in_len == element_len2) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
span,
name,
in_len,
in_ty,
arg_ty: args[2].layout.ty,
out_len: element_len2,
});
return Err(err);
};
};require!(
2812 in_len == element_len2,
2813 InvalidMonomorphization::ThirdArgumentLength {
2814 span,
2815 name,
2816 in_len,
2817 in_ty,
2818 arg_ty: args[2].layout.ty,
2819 out_len: element_len2
2820 }
2821 );
2822
2823 if !#[allow(non_exhaustive_omitted_patterns)] match *element_ty1.kind() {
ty::RawPtr(p_ty, p_mutbl) if
p_ty == in_elem && p_mutbl.is_mut() &&
p_ty.kind() == element_ty0.kind() => true,
_ => false,
} {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
span,
name,
expected_element: element_ty1,
second_arg: args[1].layout.ty,
in_elem,
in_ty,
mutability: ExpectedPointerMutability::Mut,
});
return Err(err);
};
};require!(
2824 matches!(
2825 *element_ty1.kind(),
2826 ty::RawPtr(p_ty, p_mutbl)
2827 if p_ty == in_elem && p_mutbl.is_mut() && p_ty.kind() == element_ty0.kind()
2828 ),
2829 InvalidMonomorphization::ExpectedElementType {
2830 span,
2831 name,
2832 expected_element: element_ty1,
2833 second_arg: args[1].layout.ty,
2834 in_elem,
2835 in_ty,
2836 mutability: ExpectedPointerMutability::Mut,
2837 }
2838 );
2839
2840 let mask_elem_bitwidth = match element_ty2.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
span,
name,
ty: element_ty2,
});
return Err(err);
};
}
}require_int_or_uint_ty!(
2842 element_ty2.kind(),
2843 InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
2844 );
2845
2846 let alignment = bx.align_of(in_elem).bytes();
2848
2849 let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
2851
2852 let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
2854
2855 let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
2857 let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2858 let alignment = bx.const_i32(alignment as i32);
2859 &[args[0].immediate(), args[1].immediate(), alignment, mask]
2860 } else {
2861 &[args[0].immediate(), args[1].immediate(), mask]
2862 };
2863 let call = bx.call_intrinsic(
2864 "llvm.masked.scatter",
2865 &[llvm_elem_vec_ty, llvm_pointer_vec_ty],
2866 args,
2867 );
2868 if llvm_version >= (22, 0, 0) {
2869 crate::attributes::apply_to_callsite(
2870 call,
2871 crate::llvm::AttributePlace::Argument(1),
2872 &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2873 )
2874 }
2875 return Ok(call);
2876 }
2877
2878 macro_rules! arith_red {
2879 ($name:ident : $integer_reduce:ident, $float_reduce:ident, $ordered:expr, $op:ident,
2880 $identity:expr) => {
2881 if name == sym::$name {
2882 require!(
2883 ret_ty == in_elem,
2884 InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
2885 );
2886 return match in_elem.kind() {
2887 ty::Int(_) | ty::Uint(_) => {
2888 let r = bx.$integer_reduce(args[0].immediate());
2889 if $ordered {
2890 Ok(bx.$op(args[1].immediate(), r))
2893 } else {
2894 Ok(bx.$integer_reduce(args[0].immediate()))
2895 }
2896 }
2897 ty::Float(f) => {
2898 let acc = if $ordered {
2899 args[1].immediate()
2901 } else {
2902 match f.bit_width() {
2904 32 => bx.const_real(bx.type_f32(), $identity),
2905 64 => bx.const_real(bx.type_f64(), $identity),
2906 v => return_error!(
2907 InvalidMonomorphization::UnsupportedSymbolOfSize {
2908 span,
2909 name,
2910 symbol: sym::$name,
2911 in_ty,
2912 in_elem,
2913 size: v,
2914 ret_ty
2915 }
2916 ),
2917 }
2918 };
2919 Ok(bx.$float_reduce(acc, args[0].immediate()))
2920 }
2921 _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
2922 span,
2923 name,
2924 symbol: sym::$name,
2925 in_ty,
2926 in_elem,
2927 ret_ty
2928 }),
2929 };
2930 }
2931 };
2932 }
2933
2934 if name == sym::simd_reduce_add_ordered {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_add(args[0].immediate());
if true {
Ok(bx.add(args[1].immediate(), r))
} else { Ok(bx.vector_reduce_add(args[0].immediate())) }
}
ty::Float(f) => {
let acc =
if true {
args[1].immediate()
} else {
match f.bit_width() {
32 => bx.const_real(bx.type_f32(), -0.0),
64 => bx.const_real(bx.type_f64(), -0.0),
v => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
span,
name,
symbol: sym::simd_reduce_add_ordered,
in_ty,
in_elem,
size: v,
ret_ty,
});
return Err(err);
}
}
};
Ok(bx.vector_reduce_fadd(acc, args[0].immediate()))
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_add_ordered,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, -0.0);
2935 if name == sym::simd_reduce_mul_ordered {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_mul(args[0].immediate());
if true {
Ok(bx.mul(args[1].immediate(), r))
} else { Ok(bx.vector_reduce_mul(args[0].immediate())) }
}
ty::Float(f) => {
let acc =
if true {
args[1].immediate()
} else {
match f.bit_width() {
32 => bx.const_real(bx.type_f32(), 1.0),
64 => bx.const_real(bx.type_f64(), 1.0),
v => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
span,
name,
symbol: sym::simd_reduce_mul_ordered,
in_ty,
in_elem,
size: v,
ret_ty,
});
return Err(err);
}
}
};
Ok(bx.vector_reduce_fmul(acc, args[0].immediate()))
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_mul_ordered,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0);
2936 if name == sym::simd_reduce_add_unordered {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_add(args[0].immediate());
if false {
Ok(bx.add(args[1].immediate(), r))
} else { Ok(bx.vector_reduce_add(args[0].immediate())) }
}
ty::Float(f) => {
let acc =
if false {
args[1].immediate()
} else {
match f.bit_width() {
32 => bx.const_real(bx.type_f32(), -0.0),
64 => bx.const_real(bx.type_f64(), -0.0),
v => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
span,
name,
symbol: sym::simd_reduce_add_unordered,
in_ty,
in_elem,
size: v,
ret_ty,
});
return Err(err);
}
}
};
Ok(bx.vector_reduce_fadd_reassoc(acc, args[0].immediate()))
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_add_unordered,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};arith_red!(
2937 simd_reduce_add_unordered: vector_reduce_add,
2938 vector_reduce_fadd_reassoc,
2939 false,
2940 add,
2941 -0.0
2942 );
2943 if name == sym::simd_reduce_mul_unordered {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_mul(args[0].immediate());
if false {
Ok(bx.mul(args[1].immediate(), r))
} else { Ok(bx.vector_reduce_mul(args[0].immediate())) }
}
ty::Float(f) => {
let acc =
if false {
args[1].immediate()
} else {
match f.bit_width() {
32 => bx.const_real(bx.type_f32(), 1.0),
64 => bx.const_real(bx.type_f64(), 1.0),
v => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
span,
name,
symbol: sym::simd_reduce_mul_unordered,
in_ty,
in_elem,
size: v,
ret_ty,
});
return Err(err);
}
}
};
Ok(bx.vector_reduce_fmul_reassoc(acc, args[0].immediate()))
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_mul_unordered,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};arith_red!(
2944 simd_reduce_mul_unordered: vector_reduce_mul,
2945 vector_reduce_fmul_reassoc,
2946 false,
2947 mul,
2948 1.0
2949 );
2950
2951 macro_rules! minmax_red {
2952 ($name:ident: $int_red:ident) => {
2953 if name == sym::$name {
2954 require!(
2955 ret_ty == in_elem,
2956 InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
2957 );
2958 return match in_elem.kind() {
2959 ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)),
2960 ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)),
2961 _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
2962 span,
2963 name,
2964 symbol: sym::$name,
2965 in_ty,
2966 in_elem,
2967 ret_ty
2968 }),
2969 };
2970 }
2971 };
2972 }
2973
2974 if name == sym::simd_reduce_min {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
return match in_elem.kind() {
ty::Int(_i) =>
Ok(bx.vector_reduce_min(args[0].immediate(), true)),
ty::Uint(_u) =>
Ok(bx.vector_reduce_min(args[0].immediate(), false)),
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_min,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};minmax_red!(simd_reduce_min: vector_reduce_min);
2976 if name == sym::simd_reduce_max {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
return match in_elem.kind() {
ty::Int(_i) =>
Ok(bx.vector_reduce_max(args[0].immediate(), true)),
ty::Uint(_u) =>
Ok(bx.vector_reduce_max(args[0].immediate(), false)),
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_max,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};minmax_red!(simd_reduce_max: vector_reduce_max);
2977
2978 macro_rules! bitwise_red {
2979 ($name:ident : $red:ident, $boolean:expr) => {
2980 if name == sym::$name {
2981 let input = if !$boolean {
2982 require!(
2983 ret_ty == in_elem,
2984 InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
2985 );
2986 args[0].immediate()
2987 } else {
2988 let bitwidth = match in_elem.kind() {
2989 ty::Int(i) => {
2990 i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
2991 }
2992 ty::Uint(i) => {
2993 i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
2994 }
2995 _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
2996 span,
2997 name,
2998 symbol: sym::$name,
2999 in_ty,
3000 in_elem,
3001 ret_ty
3002 }),
3003 };
3004
3005 vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth, in_len as _)
3006 };
3007 return match in_elem.kind() {
3008 ty::Int(_) | ty::Uint(_) => {
3009 let r = bx.$red(input);
3010 Ok(r)
3011 }
3012 _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
3013 span,
3014 name,
3015 symbol: sym::$name,
3016 in_ty,
3017 in_elem,
3018 ret_ty
3019 }),
3020 };
3021 }
3022 };
3023 }
3024
3025 if name == sym::simd_reduce_and {
let input =
if !false {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
args[0].immediate()
} else {
let bitwidth =
match in_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_and,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
in_len as _)
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_and(input);
Ok(r)
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_and,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};bitwise_red!(simd_reduce_and: vector_reduce_and, false);
3026 if name == sym::simd_reduce_or {
let input =
if !false {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
args[0].immediate()
} else {
let bitwidth =
match in_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_or,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
in_len as _)
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_or(input);
Ok(r)
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_or,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};bitwise_red!(simd_reduce_or: vector_reduce_or, false);
3027 if name == sym::simd_reduce_xor {
let input =
if !false {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
args[0].immediate()
} else {
let bitwidth =
match in_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_xor,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
in_len as _)
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_xor(input);
Ok(r)
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_xor,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};bitwise_red!(simd_reduce_xor: vector_reduce_xor, false);
3028 if name == sym::simd_reduce_all {
let input =
if !true {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
args[0].immediate()
} else {
let bitwidth =
match in_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_all,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
in_len as _)
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_and(input);
Ok(r)
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_all,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};bitwise_red!(simd_reduce_all: vector_reduce_and, true);
3029 if name == sym::simd_reduce_any {
let input =
if !true {
if !(ret_ty == in_elem) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
span,
name,
in_elem,
in_ty,
ret_ty,
});
return Err(err);
};
};
args[0].immediate()
} else {
let bitwidth =
match in_elem.kind() {
ty::Int(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
ty::Uint(i) => {
i.bit_width().unwrap_or_else(||
bx.data_layout().pointer_size().bits())
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_any,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
in_len as _)
};
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
let r = bx.vector_reduce_or(input);
Ok(r)
}
_ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
span,
name,
symbol: sym::simd_reduce_any,
in_ty,
in_elem,
ret_ty,
});
return Err(err);
}
};
};bitwise_red!(simd_reduce_any: vector_reduce_or, true);
3030
3031 if name == sym::simd_cast_ptr {
3032 let (out_len, out_elem) = {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
3033 if !(in_len == out_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
span,
name,
in_len,
in_ty,
ret_ty,
out_len,
});
return Err(err);
};
};require!(
3034 in_len == out_len,
3035 InvalidMonomorphization::ReturnLengthInputType {
3036 span,
3037 name,
3038 in_len,
3039 in_ty,
3040 ret_ty,
3041 out_len
3042 }
3043 );
3044
3045 match in_elem.kind() {
3046 ty::RawPtr(p_ty, _) => {
3047 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
3048 bx.tcx.normalize_erasing_regions(bx.typing_env(), ty)
3049 });
3050 if !metadata.is_unit() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::CastWidePointer {
span,
name,
ty: in_elem,
});
return Err(err);
};
};require!(
3051 metadata.is_unit(),
3052 InvalidMonomorphization::CastWidePointer { span, name, ty: in_elem }
3053 );
3054 }
3055 _ => {
3056 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
span,
name,
ty: in_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
3057 }
3058 }
3059 match out_elem.kind() {
3060 ty::RawPtr(p_ty, _) => {
3061 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
3062 bx.tcx.normalize_erasing_regions(bx.typing_env(), ty)
3063 });
3064 if !metadata.is_unit() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::CastWidePointer {
span,
name,
ty: out_elem,
});
return Err(err);
};
};require!(
3065 metadata.is_unit(),
3066 InvalidMonomorphization::CastWidePointer { span, name, ty: out_elem }
3067 );
3068 }
3069 _ => {
3070 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
span,
name,
ty: out_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
3071 }
3072 }
3073
3074 return Ok(args[0].immediate());
3075 }
3076
3077 if name == sym::simd_expose_provenance {
3078 let (out_len, out_elem) = {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
3079 if !(in_len == out_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
span,
name,
in_len,
in_ty,
ret_ty,
out_len,
});
return Err(err);
};
};require!(
3080 in_len == out_len,
3081 InvalidMonomorphization::ReturnLengthInputType {
3082 span,
3083 name,
3084 in_len,
3085 in_ty,
3086 ret_ty,
3087 out_len
3088 }
3089 );
3090
3091 match in_elem.kind() {
3092 ty::RawPtr(_, _) => {}
3093 _ => {
3094 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
span,
name,
ty: in_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
3095 }
3096 }
3097 match out_elem.kind() {
3098 ty::Uint(ty::UintTy::Usize) => {}
3099 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedUsize {
span,
name,
ty: out_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: out_elem }),
3100 }
3101
3102 return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
3103 }
3104
3105 if name == sym::simd_with_exposed_provenance {
3106 let (out_len, out_elem) = {
if !ret_ty.is_simd() {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
3107 if !(in_len == out_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
span,
name,
in_len,
in_ty,
ret_ty,
out_len,
});
return Err(err);
};
};require!(
3108 in_len == out_len,
3109 InvalidMonomorphization::ReturnLengthInputType {
3110 span,
3111 name,
3112 in_len,
3113 in_ty,
3114 ret_ty,
3115 out_len
3116 }
3117 );
3118
3119 match in_elem.kind() {
3120 ty::Uint(ty::UintTy::Usize) => {}
3121 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedUsize {
span,
name,
ty: in_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: in_elem }),
3122 }
3123 match out_elem.kind() {
3124 ty::RawPtr(_, _) => {}
3125 _ => {
3126 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
span,
name,
ty: out_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
3127 }
3128 }
3129
3130 return Ok(bx.inttoptr(args[0].immediate(), llret_ty));
3131 }
3132
3133 if name == sym::simd_cast || name == sym::simd_as {
3134 let (out_len, out_elem, out_num_vecs) = {
if !(ret_ty.is_simd() || ret_ty.is_scalable_vector()) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
span,
name,
ty: ret_ty,
});
return Err(err);
};
};
if ret_ty.is_simd() {
let (len, ty) = ret_ty.simd_size_and_type(bx.tcx());
(len, ty, None)
} else {
let (count, ty, num_vecs) =
ret_ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
(count as u64, ty, Some(num_vecs))
}
}require_simd_or_scalable!(ret_ty, SimdReturn);
3135 if !(in_len == out_len) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
span,
name,
in_len,
in_ty,
ret_ty,
out_len,
});
return Err(err);
};
};require!(
3136 in_len == out_len,
3137 InvalidMonomorphization::ReturnLengthInputType {
3138 span,
3139 name,
3140 in_len,
3141 in_ty,
3142 ret_ty,
3143 out_len
3144 }
3145 );
3146 if !(in_num_vecs == out_num_vecs) {
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnNumVecsInputType {
span,
name,
in_num_vecs: in_num_vecs.unwrap_or(NumScalableVectors(1)),
in_ty,
ret_ty,
out_num_vecs: out_num_vecs.unwrap_or(NumScalableVectors(1)),
});
return Err(err);
};
};require!(
3147 in_num_vecs == out_num_vecs,
3148 InvalidMonomorphization::ReturnNumVecsInputType {
3149 span,
3150 name,
3151 in_num_vecs: in_num_vecs.unwrap_or(NumScalableVectors(1)),
3152 in_ty,
3153 ret_ty,
3154 out_num_vecs: out_num_vecs.unwrap_or(NumScalableVectors(1))
3155 }
3156 );
3157
3158 if in_elem == out_elem {
3160 return Ok(args[0].immediate());
3161 }
3162
3163 #[derive(#[automatically_derived]
impl ::core::marker::Copy for Sign { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Sign {
#[inline]
fn clone(&self) -> Sign { *self }
}Clone)]
3164 enum Sign {
3165 Unsigned,
3166 Signed,
3167 }
3168 use Sign::*;
3169
3170 enum Style {
3171 Float,
3172 Int(Sign),
3173 Unsupported,
3174 }
3175
3176 let (in_style, in_width) = match in_elem.kind() {
3177 ty::Int(i) => (
3180 Style::Int(Signed),
3181 i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3182 ),
3183 ty::Uint(u) => (
3184 Style::Int(Unsigned),
3185 u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3186 ),
3187 ty::Float(f) => (Style::Float, f.bit_width()),
3188 _ => (Style::Unsupported, 0),
3189 };
3190 let (out_style, out_width) = match out_elem.kind() {
3191 ty::Int(i) => (
3192 Style::Int(Signed),
3193 i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3194 ),
3195 ty::Uint(u) => (
3196 Style::Int(Unsigned),
3197 u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3198 ),
3199 ty::Float(f) => (Style::Float, f.bit_width()),
3200 _ => (Style::Unsupported, 0),
3201 };
3202
3203 match (in_style, out_style) {
3204 (Style::Int(sign), Style::Int(_)) => {
3205 return Ok(match in_width.cmp(&out_width) {
3206 Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
3207 Ordering::Equal => args[0].immediate(),
3208 Ordering::Less => match sign {
3209 Sign::Signed => bx.sext(args[0].immediate(), llret_ty),
3210 Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty),
3211 },
3212 });
3213 }
3214 (Style::Int(Sign::Signed), Style::Float) => {
3215 return Ok(bx.sitofp(args[0].immediate(), llret_ty));
3216 }
3217 (Style::Int(Sign::Unsigned), Style::Float) => {
3218 return Ok(bx.uitofp(args[0].immediate(), llret_ty));
3219 }
3220 (Style::Float, Style::Int(sign)) => {
3221 return Ok(match (sign, name == sym::simd_as) {
3222 (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty),
3223 (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty),
3224 (_, true) => bx.cast_float_to_int(
3225 #[allow(non_exhaustive_omitted_patterns)] match sign {
Sign::Signed => true,
_ => false,
}matches!(sign, Sign::Signed),
3226 args[0].immediate(),
3227 llret_ty,
3228 ),
3229 });
3230 }
3231 (Style::Float, Style::Float) => {
3232 return Ok(match in_width.cmp(&out_width) {
3233 Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty),
3234 Ordering::Equal => args[0].immediate(),
3235 Ordering::Less => bx.fpext(args[0].immediate(), llret_ty),
3236 });
3237 }
3238 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedCast {
span,
name,
in_ty,
in_elem,
ret_ty,
out_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::UnsupportedCast {
3239 span,
3240 name,
3241 in_ty,
3242 in_elem,
3243 ret_ty,
3244 out_elem
3245 }),
3246 }
3247 }
3248 macro_rules! arith_binary {
3249 ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
3250 $(if name == sym::$name {
3251 match in_elem.kind() {
3252 $($(ty::$p(_))|* => {
3253 return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
3254 })*
3255 _ => {},
3256 }
3257 return_error!(
3258 InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
3259 );
3260 })*
3261 }
3262 }
3263 if name == sym::simd_minimum_number_nsz {
match in_elem.kind() {
ty::Float(_) => {
return Ok(bx.minimum_number_nsz(args[0].immediate(),
args[1].immediate()))
}
_ => {}
}
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedOperation {
span,
name,
in_ty,
in_elem,
});
return Err(err);
};
}arith_binary! {
3264 simd_add: Uint, Int => add, Float => fadd;
3265 simd_sub: Uint, Int => sub, Float => fsub;
3266 simd_mul: Uint, Int => mul, Float => fmul;
3267 simd_div: Uint => udiv, Int => sdiv, Float => fdiv;
3268 simd_rem: Uint => urem, Int => srem, Float => frem;
3269 simd_shl: Uint, Int => shl;
3270 simd_shr: Uint => lshr, Int => ashr;
3271 simd_and: Uint, Int => and;
3272 simd_or: Uint, Int => or;
3273 simd_xor: Uint, Int => xor;
3274 simd_maximum_number_nsz: Float => maximum_number_nsz;
3275 simd_minimum_number_nsz: Float => minimum_number_nsz;
3276
3277 }
3278 macro_rules! arith_unary {
3279 ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
3280 $(if name == sym::$name {
3281 match in_elem.kind() {
3282 $($(ty::$p(_))|* => {
3283 return Ok(bx.$call(args[0].immediate()))
3284 })*
3285 _ => {},
3286 }
3287 return_error!(
3288 InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
3289 );
3290 })*
3291 }
3292 }
3293 if name == sym::simd_neg {
match in_elem.kind() {
ty::Int(_) => { return Ok(bx.neg(args[0].immediate())) }
ty::Float(_) => { return Ok(bx.fneg(args[0].immediate())) }
_ => {}
}
{
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedOperation {
span,
name,
in_ty,
in_elem,
});
return Err(err);
};
}arith_unary! {
3294 simd_neg: Int => neg, Float => fneg;
3295 }
3296
3297 if #[allow(non_exhaustive_omitted_patterns)] match name {
sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop
| sym::simd_cttz | sym::simd_carryless_mul | sym::simd_funnel_shl |
sym::simd_funnel_shr => true,
_ => false,
}matches!(
3299 name,
3300 sym::simd_bswap
3301 | sym::simd_bitreverse
3302 | sym::simd_ctlz
3303 | sym::simd_ctpop
3304 | sym::simd_cttz
3305 | sym::simd_carryless_mul
3306 | sym::simd_funnel_shl
3307 | sym::simd_funnel_shr
3308 ) {
3309 let vec_ty = bx.cx.type_vector(
3310 match *in_elem.kind() {
3311 ty::Int(i) => bx.cx.type_int_from_ty(i),
3312 ty::Uint(i) => bx.cx.type_uint_from_ty(i),
3313 _ => {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedOperation {
span,
name,
in_ty,
in_elem,
});
return Err(err);
}return_error!(InvalidMonomorphization::UnsupportedOperation {
3314 span,
3315 name,
3316 in_ty,
3317 in_elem
3318 }),
3319 },
3320 in_len as u64,
3321 );
3322 let llvm_intrinsic = match name {
3323 sym::simd_bswap => "llvm.bswap",
3324 sym::simd_bitreverse => "llvm.bitreverse",
3325 sym::simd_ctlz => "llvm.ctlz",
3326 sym::simd_ctpop => "llvm.ctpop",
3327 sym::simd_cttz => "llvm.cttz",
3328 sym::simd_funnel_shl => "llvm.fshl",
3329 sym::simd_funnel_shr => "llvm.fshr",
3330 sym::simd_carryless_mul => "llvm.clmul",
3331 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
3332 };
3333 let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
3334
3335 return match name {
3336 sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()),
3338 sym::simd_ctlz | sym::simd_cttz => {
3339 let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0);
3341 Ok(bx.call_intrinsic(
3342 llvm_intrinsic,
3343 &[vec_ty],
3344 &[args[0].immediate(), dont_poison_on_zero],
3345 ))
3346 }
3347 sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => {
3348 Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()]))
3350 }
3351 sym::simd_funnel_shl | sym::simd_funnel_shr => Ok(bx.call_intrinsic(
3352 llvm_intrinsic,
3353 &[vec_ty],
3354 &[args[0].immediate(), args[1].immediate(), args[2].immediate()],
3355 )),
3356 sym::simd_carryless_mul => {
3357 if crate::llvm_util::get_version() >= (22, 0, 0) {
3358 Ok(bx.call_intrinsic(
3359 llvm_intrinsic,
3360 &[vec_ty],
3361 &[args[0].immediate(), args[1].immediate()],
3362 ))
3363 } else {
3364 ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("`simd_carryless_mul` needs LLVM 22 or higher"));span_bug!(span, "`simd_carryless_mul` needs LLVM 22 or higher");
3365 }
3366 }
3367 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
3368 };
3369 }
3370
3371 if name == sym::simd_arith_offset {
3372 let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| {
3374 ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("must be called with a vector of pointer types as first argument"))span_bug!(span, "must be called with a vector of pointer types as first argument")
3375 });
3376 let layout = bx.layout_of(pointee);
3377 let ptrs = args[0].immediate();
3378 let (_offsets_len, offsets_elem) = args[1].layout.ty.simd_size_and_type(bx.tcx());
3381 if !#[allow(non_exhaustive_omitted_patterns)] match offsets_elem.kind() {
ty::Int(ty::IntTy::Isize) | ty::Uint(ty::UintTy::Usize) => true,
_ => false,
}matches!(offsets_elem.kind(), ty::Int(ty::IntTy::Isize) | ty::Uint(ty::UintTy::Usize)) {
3382 ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("must be called with a vector of pointer-sized integers as second argument"));span_bug!(
3383 span,
3384 "must be called with a vector of pointer-sized integers as second argument"
3385 );
3386 }
3387 let offsets = args[1].immediate();
3388
3389 return Ok(bx.gep(bx.backend_type(layout), ptrs, &[offsets]));
3390 }
3391
3392 if name == sym::simd_saturating_add || name == sym::simd_saturating_sub {
3393 let lhs = args[0].immediate();
3394 let rhs = args[1].immediate();
3395 let is_add = name == sym::simd_saturating_add;
3396 let (signed, elem_ty) = match *in_elem.kind() {
3397 ty::Int(i) => (true, bx.cx.type_int_from_ty(i)),
3398 ty::Uint(i) => (false, bx.cx.type_uint_from_ty(i)),
3399 _ => {
3400 {
let err =
bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedVectorElementType {
span,
name,
expected_element: args[0].layout.ty.simd_size_and_type(bx.tcx()).1,
vector_type: args[0].layout.ty,
});
return Err(err);
};return_error!(InvalidMonomorphization::ExpectedVectorElementType {
3401 span,
3402 name,
3403 expected_element: args[0].layout.ty.simd_size_and_type(bx.tcx()).1,
3404 vector_type: args[0].layout.ty
3405 });
3406 }
3407 };
3408 let llvm_intrinsic = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("llvm.{0}{1}.sat",
if signed { 's' } else { 'u' },
if is_add { "add" } else { "sub" }))
})format!(
3409 "llvm.{}{}.sat",
3410 if signed { 's' } else { 'u' },
3411 if is_add { "add" } else { "sub" },
3412 );
3413 let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
3414
3415 return Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[lhs, rhs]));
3416 }
3417
3418 ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("unknown SIMD intrinsic"));span_bug!(span, "unknown SIMD intrinsic");
3419}