Skip to content

Commit bb587b1

Browse files
committed
Auto merge of #80652 - calebzulawski:simd-lanes, r=nagisa
Improve SIMD type element count validation Resolves rust-lang/portable-simd#53. These changes are motivated by `stdsimd` moving in the direction of const generic vectors, e.g.: ```rust #[repr(simd)] struct SimdF32<const N: usize>([f32; N]); ``` This makes a few changes: * Establishes a maximum SIMD lane count of 2^16 (65536). This value is arbitrary, but attempts to validate lane count before hitting potential errors in the backend. It's not clear what LLVM's maximum lane count is, but cranelift's appears to be much less than `usize::MAX`, at least. * Expands some SIMD intrinsics to support arbitrary lane counts. This resolves the ICE in the linked issue. * Attempts to catch invalid-sized vectors during typeck when possible. Unresolved questions: * Generic-length vectors can't be validated in typeck and are only validated after monomorphization while computing layout. This "works", but the errors simply bail out with no context beyond the name of the type. Should these errors instead return `LayoutError` or otherwise provide context in some way? As it stands, users of `stdsimd` could trivially produce monomorphization errors by making zero-length vectors. cc `@bjorn3`
2 parents 9778068 + a4bab7c commit bb587b1

28 files changed

+321
-395
lines changed

compiler/rustc_codegen_llvm/src/context.rs

+3-121
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
380380
"rust_eh_personality"
381381
};
382382
let fty = self.type_variadic_func(&[], self.type_i32());
383-
self.declare_cfn(name, fty)
383+
self.declare_cfn(name, llvm::UnnamedAddr::Global, fty)
384384
}
385385
};
386386
attributes::apply_target_cpu_attr(self, llfn);
@@ -429,7 +429,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
429429

430430
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
431431
if self.get_declared_value("main").is_none() {
432-
Some(self.declare_cfn("main", fn_type))
432+
Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type))
433433
} else {
434434
// If the symbol already exists, it is an error: for example, the user wrote
435435
// #[no_mangle] extern "C" fn main(..) {..}
@@ -459,8 +459,7 @@ impl CodegenCx<'b, 'tcx> {
459459
} else {
460460
self.type_variadic_func(&[], ret)
461461
};
462-
let f = self.declare_cfn(name, fn_ty);
463-
llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
462+
let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty);
464463
self.intrinsics.borrow_mut().insert(name, f);
465464
f
466465
}
@@ -498,25 +497,6 @@ impl CodegenCx<'b, 'tcx> {
498497
let t_f32 = self.type_f32();
499498
let t_f64 = self.type_f64();
500499

501-
macro_rules! vector_types {
502-
($id_out:ident: $elem_ty:ident, $len:expr) => {
503-
let $id_out = self.type_vector($elem_ty, $len);
504-
};
505-
($($id_out:ident: $elem_ty:ident, $len:expr;)*) => {
506-
$(vector_types!($id_out: $elem_ty, $len);)*
507-
}
508-
}
509-
vector_types! {
510-
t_v2f32: t_f32, 2;
511-
t_v4f32: t_f32, 4;
512-
t_v8f32: t_f32, 8;
513-
t_v16f32: t_f32, 16;
514-
515-
t_v2f64: t_f64, 2;
516-
t_v4f64: t_f64, 4;
517-
t_v8f64: t_f64, 8;
518-
}
519-
520500
ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f32", fn(t_f32) -> t_i32);
521501
ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f64", fn(t_f64) -> t_i32);
522502
ifn!("llvm.wasm.trunc.saturate.unsigned.i64.f32", fn(t_f32) -> t_i64);
@@ -540,149 +520,51 @@ impl CodegenCx<'b, 'tcx> {
540520
ifn!("llvm.sideeffect", fn() -> void);
541521

542522
ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
543-
ifn!("llvm.powi.v2f32", fn(t_v2f32, t_i32) -> t_v2f32);
544-
ifn!("llvm.powi.v4f32", fn(t_v4f32, t_i32) -> t_v4f32);
545-
ifn!("llvm.powi.v8f32", fn(t_v8f32, t_i32) -> t_v8f32);
546-
ifn!("llvm.powi.v16f32", fn(t_v16f32, t_i32) -> t_v16f32);
547523
ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
548-
ifn!("llvm.powi.v2f64", fn(t_v2f64, t_i32) -> t_v2f64);
549-
ifn!("llvm.powi.v4f64", fn(t_v4f64, t_i32) -> t_v4f64);
550-
ifn!("llvm.powi.v8f64", fn(t_v8f64, t_i32) -> t_v8f64);
551524

552525
ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
553-
ifn!("llvm.pow.v2f32", fn(t_v2f32, t_v2f32) -> t_v2f32);
554-
ifn!("llvm.pow.v4f32", fn(t_v4f32, t_v4f32) -> t_v4f32);
555-
ifn!("llvm.pow.v8f32", fn(t_v8f32, t_v8f32) -> t_v8f32);
556-
ifn!("llvm.pow.v16f32", fn(t_v16f32, t_v16f32) -> t_v16f32);
557526
ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64);
558-
ifn!("llvm.pow.v2f64", fn(t_v2f64, t_v2f64) -> t_v2f64);
559-
ifn!("llvm.pow.v4f64", fn(t_v4f64, t_v4f64) -> t_v4f64);
560-
ifn!("llvm.pow.v8f64", fn(t_v8f64, t_v8f64) -> t_v8f64);
561527

562528
ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32);
563-
ifn!("llvm.sqrt.v2f32", fn(t_v2f32) -> t_v2f32);
564-
ifn!("llvm.sqrt.v4f32", fn(t_v4f32) -> t_v4f32);
565-
ifn!("llvm.sqrt.v8f32", fn(t_v8f32) -> t_v8f32);
566-
ifn!("llvm.sqrt.v16f32", fn(t_v16f32) -> t_v16f32);
567529
ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64);
568-
ifn!("llvm.sqrt.v2f64", fn(t_v2f64) -> t_v2f64);
569-
ifn!("llvm.sqrt.v4f64", fn(t_v4f64) -> t_v4f64);
570-
ifn!("llvm.sqrt.v8f64", fn(t_v8f64) -> t_v8f64);
571530

572531
ifn!("llvm.sin.f32", fn(t_f32) -> t_f32);
573-
ifn!("llvm.sin.v2f32", fn(t_v2f32) -> t_v2f32);
574-
ifn!("llvm.sin.v4f32", fn(t_v4f32) -> t_v4f32);
575-
ifn!("llvm.sin.v8f32", fn(t_v8f32) -> t_v8f32);
576-
ifn!("llvm.sin.v16f32", fn(t_v16f32) -> t_v16f32);
577532
ifn!("llvm.sin.f64", fn(t_f64) -> t_f64);
578-
ifn!("llvm.sin.v2f64", fn(t_v2f64) -> t_v2f64);
579-
ifn!("llvm.sin.v4f64", fn(t_v4f64) -> t_v4f64);
580-
ifn!("llvm.sin.v8f64", fn(t_v8f64) -> t_v8f64);
581533

582534
ifn!("llvm.cos.f32", fn(t_f32) -> t_f32);
583-
ifn!("llvm.cos.v2f32", fn(t_v2f32) -> t_v2f32);
584-
ifn!("llvm.cos.v4f32", fn(t_v4f32) -> t_v4f32);
585-
ifn!("llvm.cos.v8f32", fn(t_v8f32) -> t_v8f32);
586-
ifn!("llvm.cos.v16f32", fn(t_v16f32) -> t_v16f32);
587535
ifn!("llvm.cos.f64", fn(t_f64) -> t_f64);
588-
ifn!("llvm.cos.v2f64", fn(t_v2f64) -> t_v2f64);
589-
ifn!("llvm.cos.v4f64", fn(t_v4f64) -> t_v4f64);
590-
ifn!("llvm.cos.v8f64", fn(t_v8f64) -> t_v8f64);
591536

592537
ifn!("llvm.exp.f32", fn(t_f32) -> t_f32);
593-
ifn!("llvm.exp.v2f32", fn(t_v2f32) -> t_v2f32);
594-
ifn!("llvm.exp.v4f32", fn(t_v4f32) -> t_v4f32);
595-
ifn!("llvm.exp.v8f32", fn(t_v8f32) -> t_v8f32);
596-
ifn!("llvm.exp.v16f32", fn(t_v16f32) -> t_v16f32);
597538
ifn!("llvm.exp.f64", fn(t_f64) -> t_f64);
598-
ifn!("llvm.exp.v2f64", fn(t_v2f64) -> t_v2f64);
599-
ifn!("llvm.exp.v4f64", fn(t_v4f64) -> t_v4f64);
600-
ifn!("llvm.exp.v8f64", fn(t_v8f64) -> t_v8f64);
601539

602540
ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32);
603-
ifn!("llvm.exp2.v2f32", fn(t_v2f32) -> t_v2f32);
604-
ifn!("llvm.exp2.v4f32", fn(t_v4f32) -> t_v4f32);
605-
ifn!("llvm.exp2.v8f32", fn(t_v8f32) -> t_v8f32);
606-
ifn!("llvm.exp2.v16f32", fn(t_v16f32) -> t_v16f32);
607541
ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64);
608-
ifn!("llvm.exp2.v2f64", fn(t_v2f64) -> t_v2f64);
609-
ifn!("llvm.exp2.v4f64", fn(t_v4f64) -> t_v4f64);
610-
ifn!("llvm.exp2.v8f64", fn(t_v8f64) -> t_v8f64);
611542

612543
ifn!("llvm.log.f32", fn(t_f32) -> t_f32);
613-
ifn!("llvm.log.v2f32", fn(t_v2f32) -> t_v2f32);
614-
ifn!("llvm.log.v4f32", fn(t_v4f32) -> t_v4f32);
615-
ifn!("llvm.log.v8f32", fn(t_v8f32) -> t_v8f32);
616-
ifn!("llvm.log.v16f32", fn(t_v16f32) -> t_v16f32);
617544
ifn!("llvm.log.f64", fn(t_f64) -> t_f64);
618-
ifn!("llvm.log.v2f64", fn(t_v2f64) -> t_v2f64);
619-
ifn!("llvm.log.v4f64", fn(t_v4f64) -> t_v4f64);
620-
ifn!("llvm.log.v8f64", fn(t_v8f64) -> t_v8f64);
621545

622546
ifn!("llvm.log10.f32", fn(t_f32) -> t_f32);
623-
ifn!("llvm.log10.v2f32", fn(t_v2f32) -> t_v2f32);
624-
ifn!("llvm.log10.v4f32", fn(t_v4f32) -> t_v4f32);
625-
ifn!("llvm.log10.v8f32", fn(t_v8f32) -> t_v8f32);
626-
ifn!("llvm.log10.v16f32", fn(t_v16f32) -> t_v16f32);
627547
ifn!("llvm.log10.f64", fn(t_f64) -> t_f64);
628-
ifn!("llvm.log10.v2f64", fn(t_v2f64) -> t_v2f64);
629-
ifn!("llvm.log10.v4f64", fn(t_v4f64) -> t_v4f64);
630-
ifn!("llvm.log10.v8f64", fn(t_v8f64) -> t_v8f64);
631548

632549
ifn!("llvm.log2.f32", fn(t_f32) -> t_f32);
633-
ifn!("llvm.log2.v2f32", fn(t_v2f32) -> t_v2f32);
634-
ifn!("llvm.log2.v4f32", fn(t_v4f32) -> t_v4f32);
635-
ifn!("llvm.log2.v8f32", fn(t_v8f32) -> t_v8f32);
636-
ifn!("llvm.log2.v16f32", fn(t_v16f32) -> t_v16f32);
637550
ifn!("llvm.log2.f64", fn(t_f64) -> t_f64);
638-
ifn!("llvm.log2.v2f64", fn(t_v2f64) -> t_v2f64);
639-
ifn!("llvm.log2.v4f64", fn(t_v4f64) -> t_v4f64);
640-
ifn!("llvm.log2.v8f64", fn(t_v8f64) -> t_v8f64);
641551

642552
ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
643-
ifn!("llvm.fma.v2f32", fn(t_v2f32, t_v2f32, t_v2f32) -> t_v2f32);
644-
ifn!("llvm.fma.v4f32", fn(t_v4f32, t_v4f32, t_v4f32) -> t_v4f32);
645-
ifn!("llvm.fma.v8f32", fn(t_v8f32, t_v8f32, t_v8f32) -> t_v8f32);
646-
ifn!("llvm.fma.v16f32", fn(t_v16f32, t_v16f32, t_v16f32) -> t_v16f32);
647553
ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
648-
ifn!("llvm.fma.v2f64", fn(t_v2f64, t_v2f64, t_v2f64) -> t_v2f64);
649-
ifn!("llvm.fma.v4f64", fn(t_v4f64, t_v4f64, t_v4f64) -> t_v4f64);
650-
ifn!("llvm.fma.v8f64", fn(t_v8f64, t_v8f64, t_v8f64) -> t_v8f64);
651554

652555
ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
653-
ifn!("llvm.fabs.v2f32", fn(t_v2f32) -> t_v2f32);
654-
ifn!("llvm.fabs.v4f32", fn(t_v4f32) -> t_v4f32);
655-
ifn!("llvm.fabs.v8f32", fn(t_v8f32) -> t_v8f32);
656-
ifn!("llvm.fabs.v16f32", fn(t_v16f32) -> t_v16f32);
657556
ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
658-
ifn!("llvm.fabs.v2f64", fn(t_v2f64) -> t_v2f64);
659-
ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64);
660-
ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64);
661557

662558
ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
663559
ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
664560
ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
665561
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
666562

667563
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
668-
ifn!("llvm.floor.v2f32", fn(t_v2f32) -> t_v2f32);
669-
ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32);
670-
ifn!("llvm.floor.v8f32", fn(t_v8f32) -> t_v8f32);
671-
ifn!("llvm.floor.v16f32", fn(t_v16f32) -> t_v16f32);
672564
ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
673-
ifn!("llvm.floor.v2f64", fn(t_v2f64) -> t_v2f64);
674-
ifn!("llvm.floor.v4f64", fn(t_v4f64) -> t_v4f64);
675-
ifn!("llvm.floor.v8f64", fn(t_v8f64) -> t_v8f64);
676565

677566
ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32);
678-
ifn!("llvm.ceil.v2f32", fn(t_v2f32) -> t_v2f32);
679-
ifn!("llvm.ceil.v4f32", fn(t_v4f32) -> t_v4f32);
680-
ifn!("llvm.ceil.v8f32", fn(t_v8f32) -> t_v8f32);
681-
ifn!("llvm.ceil.v16f32", fn(t_v16f32) -> t_v16f32);
682567
ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64);
683-
ifn!("llvm.ceil.v2f64", fn(t_v2f64) -> t_v2f64);
684-
ifn!("llvm.ceil.v4f64", fn(t_v4f64) -> t_v4f64);
685-
ifn!("llvm.ceil.v8f64", fn(t_v8f64) -> t_v8f64);
686568

687569
ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32);
688570
ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64);

compiler/rustc_codegen_llvm/src/declare.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ fn declare_raw_fn(
3030
cx: &CodegenCx<'ll, '_>,
3131
name: &str,
3232
callconv: llvm::CallConv,
33+
unnamed: llvm::UnnamedAddr,
3334
ty: &'ll Type,
3435
) -> &'ll Value {
3536
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
@@ -38,9 +39,7 @@ fn declare_raw_fn(
3839
};
3940

4041
llvm::SetFunctionCallConv(llfn, callconv);
41-
// Function addresses in Rust are never significant, allowing functions to
42-
// be merged.
43-
llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global);
42+
llvm::SetUnnamedAddress(llfn, unnamed);
4443

4544
if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
4645
llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
@@ -68,8 +67,13 @@ impl CodegenCx<'ll, 'tcx> {
6867
///
6968
/// If there’s a value with the same name already declared, the function will
7069
/// update the declaration and return existing Value instead.
71-
pub fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value {
72-
declare_raw_fn(self, name, llvm::CCallConv, fn_type)
70+
pub fn declare_cfn(
71+
&self,
72+
name: &str,
73+
unnamed: llvm::UnnamedAddr,
74+
fn_type: &'ll Type,
75+
) -> &'ll Value {
76+
declare_raw_fn(self, name, llvm::CCallConv, unnamed, fn_type)
7377
}
7478

7579
/// Declare a Rust function.
@@ -79,7 +83,15 @@ impl CodegenCx<'ll, 'tcx> {
7983
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value {
8084
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
8185

82-
let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self));
86+
// Function addresses in Rust are never significant, allowing functions to
87+
// be merged.
88+
let llfn = declare_raw_fn(
89+
self,
90+
name,
91+
fn_abi.llvm_cconv(),
92+
llvm::UnnamedAddr::Global,
93+
fn_abi.llvm_type(self),
94+
);
8395
fn_abi.apply_attrs_llfn(self, llfn);
8496
llfn
8597
}

0 commit comments

Comments
 (0)