diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9cb36ce7f1890..4ea5d8cb7de30 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -561,6 +561,19 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { count: u64, dest: PlaceRef<'tcx, &'ll Value>, ) -> Self { + if let OperandValue::Pair(mut v1, mut v2) = cg_elem.val { + v1 = self.from_immediate(v1); + v2 = self.from_immediate(v2); + let ty = self.cx().val_ty(v1); + // Create a vector of size 2*count and store it in one instruction + if ty == self.cx().val_ty(v2) { + let vec = self.vector_repeat_two(v1, v2, count as usize); + let vec = OperandRef::from_immediate_or_packed_pair(&mut self, vec, dest.layout); + vec.val.store(&mut self, dest); + return self; + } + } + let zero = self.const_usize(0); let count = self.const_usize(count); let start = dest.project_index(&mut self, zero).llval; @@ -1328,6 +1341,27 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed) } } + // (v1, v2, 3) -> [v1, v2, v1, v2, v1, v2] + pub fn vector_repeat_two( + &mut self, + v1: &'ll Value, + v2: &'ll Value, + times: usize, + ) -> &'ll Value { + let ty = self.cx().val_ty(v1); + debug_assert!(ty == self.cx().val_ty(v2)); + // shufflevector <2 x i8> , <2 x i8> undef, <(timesx2) x i32> + let undef = unsafe { llvm::LLVMGetUndef(self.type_vector(ty, 2)) }; + let vec1 = self.insert_element(undef, v1, self.const_i32(0)); + let vec1 = self.insert_element(vec1, v2, self.const_i32(1)); + let mask = std::iter::repeat([self.const_i32(0), self.const_i32(1)]) + .take(times) + .flatten() + .collect::>(); + let mask = self.const_vector(&mask); + self.shuffle_vector(vec1, undef, mask) + } + pub fn add_clause(&mut self, landing_pad: &'ll Value, clause: &'ll Value) { unsafe { llvm::LLVMAddClause(landing_pad, clause); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index e6ba642a7ed0e..5d854e397c139 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -12,8 +12,6 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; use rustc_target::abi::{Abi, Align, Size}; -use std::fmt; - /// The representation of a Rust value. The enum variant is in fact /// uniquely determined by the value's type, but is kept as a /// safety check. @@ -38,7 +36,7 @@ pub enum OperandValue { /// to avoid nasty edge cases. In particular, using `Builder::store` /// directly is sure to cause problems -- use `OperandRef::store` /// instead. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct OperandRef<'tcx, V> { // The value. pub val: OperandValue, @@ -47,12 +45,6 @@ pub struct OperandRef<'tcx, V> { pub layout: TyAndLayout<'tcx>, } -impl fmt::Debug for OperandRef<'_, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout) - } -} - impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { pub fn new_zst>( bx: &mut Bx, diff --git a/src/test/codegen/enum-repeat.rs b/src/test/codegen/enum-repeat.rs new file mode 100644 index 0000000000000..4b85c6bef9edf --- /dev/null +++ b/src/test/codegen/enum-repeat.rs @@ -0,0 +1,19 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @none_repeat +#[no_mangle] +pub fn none_repeat() -> [Option; 64] { + // CHECK: store <128 x i8> + // CHECK-NEXT: ret void + [None; 64] +} + +// CHECK-LABEL: @some_repeat +#[no_mangle] +pub fn some_repeat() -> [Option; 64] { + // CHECK: store <128 x i8> + // CHECK-NEXT: ret void + [Some(0); 64] +}