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