From c1b1d733e4686ea443b4cadd3da558fc05ff5ee8 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 13 Nov 2022 23:16:44 +0000 Subject: [PATCH 1/2] Improve codegen for arrays of repeated enums --- compiler/rustc_codegen_llvm/src/builder.rs | 18 ++++++++++++++++++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 10 +--------- src/test/codegen/enum-repeat.rs | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 src/test/codegen/enum-repeat.rs diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9cb36ce7f1890..72946834e4440 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -561,6 +561,24 @@ 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 && count < 1024 { + 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 count = count * 2; + let vec = unsafe { llvm::LLVMGetUndef(self.type_vector(ty, count as u64)) }; + let vec = (0..count as usize).fold(vec, |acc, x| { + let elt = [v1, v2][x % 2]; + self.insert_element(acc, elt, self.cx.const_i32(x as i32)) + }); + 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; 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] +} From 4c12ecf097c484b027d273390919bf3f2a138d6c Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 14 Nov 2022 10:18:09 +0000 Subject: [PATCH 2/2] Repeat elements with `shuffle_vector` --- compiler/rustc_codegen_llvm/src/builder.rs | 30 +++++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 72946834e4440..4ea5d8cb7de30 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -561,18 +561,13 @@ 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 && count < 1024 { + 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 count = count * 2; - let vec = unsafe { llvm::LLVMGetUndef(self.type_vector(ty, count as u64)) }; - let vec = (0..count as usize).fold(vec, |acc, x| { - let elt = [v1, v2][x % 2]; - self.insert_element(acc, elt, self.cx.const_i32(x as i32)) - }); + 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; @@ -1346,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);