Skip to content

Commit 77b7310

Browse files
committed
Add #[rustc_intrinsic_const_vector_arg] to allow vectors to be passed as constants
This allows constant vectors using a repr(simd) type to be propagated through to the backend by reusing the functionality used to do a similar thing for the simd_shuffle intrinsic. fix #118209
1 parent 96df494 commit 77b7310

File tree

24 files changed

+460
-33
lines changed

24 files changed

+460
-33
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3496,6 +3496,7 @@ dependencies = [
34963496
"either",
34973497
"itertools",
34983498
"polonius-engine",
3499+
"rustc_ast",
34993500
"rustc_data_structures",
35003501
"rustc_errors",
35013502
"rustc_fluent_macro",

compiler/rustc_borrowck/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2021"
88
either = "1.5.0"
99
itertools = "0.11"
1010
polonius-engine = "0.13.0"
11+
rustc_ast = { path = "../rustc_ast" }
1112
rustc_data_structures = { path = "../rustc_data_structures" }
1213
rustc_errors = { path = "../rustc_errors" }
1314
rustc_fluent_macro = { path = "../rustc_fluent_macro" }

compiler/rustc_borrowck/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ borrowck_higher_ranked_lifetime_error =
7171
borrowck_higher_ranked_subtype_error =
7272
higher-ranked subtype error
7373
74+
borrowck_intrinsic_const_vector_arg_non_const = argument at index {$index} must be a constant
75+
7476
borrowck_lifetime_constraints_error =
7577
lifetime may not live long enough
7678

compiler/rustc_borrowck/src/session_diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,3 +459,11 @@ pub(crate) struct SimdShuffleLastConst {
459459
#[primary_span]
460460
pub span: Span,
461461
}
462+
463+
#[derive(Diagnostic)]
464+
#[diag(borrowck_intrinsic_const_vector_arg_non_const)]
465+
pub(crate) struct IntrinsicConstVectorArgNonConst {
466+
#[primary_span]
467+
pub span: Span,
468+
pub index: u128,
469+
}

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
4949
use rustc_mir_dataflow::move_paths::MoveData;
5050
use rustc_mir_dataflow::ResultsCursor;
5151

52-
use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
52+
use crate::session_diagnostics::{
53+
IntrinsicConstVectorArgNonConst, MoveUnsized, SimdShuffleLastConst,
54+
};
5355
use crate::{
5456
borrow_set::BorrowSet,
5557
constraints::{OutlivesConstraint, OutlivesConstraintSet},
@@ -1579,6 +1581,35 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
15791581
}
15801582
_ => {}
15811583
}
1584+
} else if let Some(attr) =
1585+
self.tcx().get_attr(def_id, sym::rustc_intrinsic_const_vector_arg)
1586+
{
1587+
match attr.meta_item_list() {
1588+
Some(items) => {
1589+
items.into_iter().for_each(|item: rustc_ast::NestedMetaItem| match item {
1590+
rustc_ast::NestedMetaItem::Lit(rustc_ast::MetaItemLit {
1591+
kind: rustc_ast::LitKind::Int(index, _),
1592+
..
1593+
}) => {
1594+
if index >= args.len() as u128 {
1595+
span_mirbug!(self, term, "index out of bounds");
1596+
} else {
1597+
if !matches!(args[index as usize], Operand::Constant(_)) {
1598+
self.tcx().sess.emit_err(IntrinsicConstVectorArgNonConst {
1599+
span: term.source_info.span,
1600+
index,
1601+
});
1602+
}
1603+
}
1604+
}
1605+
_ => {
1606+
span_mirbug!(self, term, "invalid index");
1607+
}
1608+
});
1609+
}
1610+
// Error is reported by `rustc_attr!`
1611+
None => (),
1612+
}
15821613
}
15831614
}
15841615
debug!(?func_ty);

compiler/rustc_codegen_gcc/src/common.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
159159
self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
160160
}
161161

162+
fn const_vector(&self, values: &[RValue<'gcc>]) -> RValue<'gcc> {
163+
let typ = self.type_vector(values[0].get_type(), values.len() as u64);
164+
self.context.new_rvalue_from_vector(None, typ, values)
165+
}
166+
162167
fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
163168
// TODO(antoyo)
164169
None

compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ impl<'ll> CodegenCx<'ll, '_> {
9898
unsafe { llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint) }
9999
}
100100

101-
pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
102-
unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) }
103-
}
104-
105101
pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
106102
bytes_in_context(self.llcx, bytes)
107103
}
@@ -217,6 +213,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
217213
struct_in_context(self.llcx, elts, packed)
218214
}
219215

216+
fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
217+
unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) }
218+
}
219+
220220
fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
221221
try_as_const_integral(v).and_then(|v| unsafe {
222222
let mut i = 0u64;

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ codegen_ssa_cgu_not_recorded =
1616
1717
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
1818
19+
codegen_ssa_const_vector_evaluation = could not evaluate constant vector at compile time
20+
1921
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
2022
2123
codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,13 @@ pub struct ShuffleIndicesEvaluation {
663663
pub span: Span,
664664
}
665665

666+
#[derive(Diagnostic)]
667+
#[diag(codegen_ssa_const_vector_evaluation)]
668+
pub struct ConstVectorEvaluation {
669+
#[primary_span]
670+
pub span: Span,
671+
}
672+
666673
#[derive(Diagnostic)]
667674
#[diag(codegen_ssa_missing_memory_ordering)]
668675
pub struct MissingMemoryOrdering;

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use super::{CachedLlbb, FunctionCx, LocalRef};
55

66
use crate::base;
77
use crate::common::{self, IntPredicate};
8+
use crate::errors;
89
use crate::meth;
910
use crate::traits::*;
1011
use crate::MemFlags;
1112

1213
use rustc_ast as ast;
13-
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
14+
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, LitKind, MetaItemLit, NestedMetaItem};
1415
use rustc_hir::lang_items::LangItem;
1516
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
1617
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
@@ -864,7 +865,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
864865
// promotes any complex rvalues to constants.
865866
if i == 2 && intrinsic == sym::simd_shuffle {
866867
if let mir::Operand::Constant(constant) = arg {
867-
let (llval, ty) = self.simd_shuffle_indices(bx, constant);
868+
let (llval, ty) = self.early_evaluate_const_vector(bx, constant);
869+
let llval = llval.unwrap_or_else(|| {
870+
bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation {
871+
span: constant.span,
872+
});
873+
// We've errored, so we don't have to produce working code.
874+
let llty = bx.backend_type(bx.layout_of(ty));
875+
bx.const_undef(llty)
876+
});
868877
return OperandRef {
869878
val: Immediate(llval),
870879
layout: bx.layout_of(ty),
@@ -908,9 +917,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
908917
(args, None)
909918
};
910919

920+
let const_vec_arg_indexes = (|| {
921+
if let Some(def) = def
922+
&& let Some(attr) =
923+
bx.tcx().get_attr(def.def_id(), sym::rustc_intrinsic_const_vector_arg)
924+
{
925+
attr.meta_item_list()
926+
.iter()
927+
.flatten()
928+
.map(|item: &NestedMetaItem| match item {
929+
NestedMetaItem::Lit(MetaItemLit {
930+
kind: LitKind::Int(index, _), ..
931+
}) => *index as usize,
932+
_ => span_bug!(item.span(), "attribute argument must be an integer"),
933+
})
934+
.collect()
935+
} else {
936+
Vec::<usize>::new()
937+
}
938+
})();
939+
911940
let mut copied_constant_arguments = vec![];
912941
'make_args: for (i, arg) in first_args.iter().enumerate() {
913-
let mut op = self.codegen_operand(bx, arg);
942+
let mut op = if const_vec_arg_indexes.contains(&i) {
943+
// Force the specified argument to be constant by using const-qualification to promote any complex rvalues to constant.
944+
if let mir::Operand::Constant(constant) = arg
945+
&& constant.ty().is_simd()
946+
{
947+
let (llval, ty) = self.early_evaluate_const_vector(bx, &constant);
948+
let llval = llval.unwrap_or_else(|| {
949+
bx.tcx()
950+
.sess
951+
.emit_err(errors::ConstVectorEvaluation { span: constant.span });
952+
// We've errored, so we don't have to produce working code.
953+
let llty = bx.backend_type(bx.layout_of(ty));
954+
bx.const_undef(llty)
955+
});
956+
OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) }
957+
} else {
958+
span_bug!(span, "argument at {i} must be a constant vector");
959+
}
960+
} else {
961+
self.codegen_operand(bx, arg)
962+
};
914963

915964
if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) {
916965
match op.val {

0 commit comments

Comments
 (0)