Skip to content

Commit 06b2dc0

Browse files
GeorgeWortJamesbarford
authored andcommitted
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 rust-lang#118209
1 parent aee3dc4 commit 06b2dc0

File tree

24 files changed

+455
-24
lines changed

24 files changed

+455
-24
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3779,6 +3779,7 @@ dependencies = [
37793779
"either",
37803780
"itertools",
37813781
"polonius-engine",
3782+
"rustc_ast",
37823783
"rustc_data_structures",
37833784
"rustc_errors",
37843785
"rustc_fluent_macro",

compiler/rustc_borrowck/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2021"
88
either = "1.5.0"
99
itertools = "0.12"
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

+2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ borrowck_higher_ranked_lifetime_error =
7474
borrowck_higher_ranked_subtype_error =
7575
higher-ranked subtype error
7676
77+
borrowck_intrinsic_const_vector_arg_non_const = argument at index {$index} must be a constant
78+
7779
borrowck_lifetime_constraints_error =
7880
lifetime may not live long enough
7981

compiler/rustc_borrowck/src/session_diagnostics.rs

+8
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,11 @@ pub(crate) struct SimdIntrinsicArgConst {
479479
pub arg: usize,
480480
pub intrinsic: String,
481481
}
482+
483+
#[derive(Diagnostic)]
484+
#[diag(borrowck_intrinsic_const_vector_arg_non_const)]
485+
pub(crate) struct IntrinsicConstVectorArgNonConst {
486+
#[primary_span]
487+
pub span: Span,
488+
pub index: u128,
489+
}

compiler/rustc_borrowck/src/type_check/mod.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ use rustc_mir_dataflow::move_paths::MoveData;
5151
use rustc_mir_dataflow::ResultsCursor;
5252

5353
use crate::renumber::RegionCtxt;
54-
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
54+
use crate::session_diagnostics::{
55+
IntrinsicConstVectorArgNonConst, MoveUnsized, SimdShuffleLastConst,
56+
};
5557
use crate::{
5658
borrow_set::BorrowSet,
5759
constraints::{OutlivesConstraint, OutlivesConstraintSet},
@@ -1630,6 +1632,35 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16301632
intrinsic: name.to_string(),
16311633
});
16321634
}
1635+
} else if let Some(attr) =
1636+
self.tcx().get_attr(def_id, sym::rustc_intrinsic_const_vector_arg)
1637+
{
1638+
match attr.meta_item_list() {
1639+
Some(items) => {
1640+
items.into_iter().for_each(|item: rustc_ast::NestedMetaItem| match item {
1641+
rustc_ast::NestedMetaItem::Lit(rustc_ast::MetaItemLit {
1642+
kind: rustc_ast::LitKind::Int(index, _),
1643+
..
1644+
}) => {
1645+
if index >= args.len() as u128 {
1646+
span_mirbug!(self, term, "index out of bounds");
1647+
} else {
1648+
if !matches!(args[index as usize], Operand::Constant(_)) {
1649+
self.tcx().sess.emit_err(IntrinsicConstVectorArgNonConst {
1650+
span: term.source_info.span,
1651+
index,
1652+
});
1653+
}
1654+
}
1655+
}
1656+
_ => {
1657+
span_mirbug!(self, term, "invalid index");
1658+
}
1659+
});
1660+
}
1661+
// Error is reported by `rustc_attr!`
1662+
None => (),
1663+
}
16331664
}
16341665
}
16351666
debug!(?func_ty);

compiler/rustc_codegen_gcc/src/common.rs

+5
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
161161
self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
162162
}
163163

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

compiler/rustc_codegen_llvm/src/common.rs

+4
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
224224
struct_in_context(self.llcx, elts, packed)
225225
}
226226

227+
fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
228+
unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) }
229+
}
230+
227231
fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
228232
try_as_const_integral(v).and_then(|v| unsafe {
229233
let mut i = 0u64;

compiler/rustc_codegen_ssa/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 201
1919
codegen_ssa_compiler_builtins_cannot_call =
2020
`compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `{$caller}` to `{$callee}`
2121
22+
codegen_ssa_const_vector_evaluation = could not evaluate constant vector at compile time
23+
2224
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
2325
2426
codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}

compiler/rustc_codegen_ssa/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,13 @@ pub struct ShuffleIndicesEvaluation {
598598
pub span: Span,
599599
}
600600

601+
#[derive(Diagnostic)]
602+
#[diag(codegen_ssa_const_vector_evaluation)]
603+
pub struct ConstVectorEvaluation {
604+
#[primary_span]
605+
pub span: Span,
606+
}
607+
601608
#[derive(Diagnostic)]
602609
#[diag(codegen_ssa_missing_memory_ordering)]
603610
pub struct MissingMemoryOrdering;

compiler/rustc_codegen_ssa/src/mir/block.rs

+52-4
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use super::{CachedLlbb, FunctionCx, LocalRef};
55

66
use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
77
use crate::common::{self, IntPredicate};
8-
use crate::errors::CompilerBuiltinsCannotCall;
8+
use crate::errors;
99
use crate::meth;
1010
use crate::traits::*;
1111
use crate::MemFlags;
1212

1313
use rustc_ast as ast;
14-
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
14+
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, LitKind, MetaItemLit, NestedMetaItem};
1515
use rustc_hir::lang_items::LangItem;
1616
use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason};
1717
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
@@ -925,7 +925,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
925925
// checked by the type-checker.
926926
if i == 2 && intrinsic.name == sym::simd_shuffle {
927927
if let mir::Operand::Constant(constant) = &arg.node {
928-
let (llval, ty) = self.simd_shuffle_indices(bx, constant);
928+
let (llval, ty) = self.early_evaluate_const_vector(bx, constant);
929+
let llval = llval.unwrap_or_else(|| {
930+
bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation {
931+
span: constant.span,
932+
});
933+
// We've errored, so we don't have to produce working code.
934+
let llty = bx.backend_type(bx.layout_of(ty));
935+
bx.const_undef(llty)
936+
});
929937
return OperandRef {
930938
val: Immediate(llval),
931939
layout: bx.layout_of(ty),
@@ -1003,9 +1011,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10031011
(args, None)
10041012
};
10051013

1014+
let const_vec_arg_indexes = (|| {
1015+
if let Some(def) = def
1016+
&& let Some(attr) =
1017+
bx.tcx().get_attr(def.def_id(), sym::rustc_intrinsic_const_vector_arg)
1018+
{
1019+
attr.meta_item_list()
1020+
.iter()
1021+
.flatten()
1022+
.map(|item: &NestedMetaItem| match item {
1023+
NestedMetaItem::Lit(MetaItemLit {
1024+
kind: LitKind::Int(index, _), ..
1025+
}) => *index as usize,
1026+
_ => span_bug!(item.span(), "attribute argument must be an integer"),
1027+
})
1028+
.collect()
1029+
} else {
1030+
Vec::<usize>::new()
1031+
}
1032+
})();
1033+
10061034
let mut copied_constant_arguments = vec![];
10071035
'make_args: for (i, arg) in first_args.iter().enumerate() {
1008-
let mut op = self.codegen_operand(bx, &arg.node);
1036+
let mut op = if const_vec_arg_indexes.contains(&i) {
1037+
// Force the specified argument to be constant by using const-qualification to promote any complex rvalues to constant.
1038+
if let mir::Operand::Constant(constant) = &arg.node
1039+
&& constant.ty().is_simd()
1040+
{
1041+
let (llval, ty) = self.early_evaluate_const_vector(bx, &constant);
1042+
let llval = llval.unwrap_or_else(|| {
1043+
bx.tcx()
1044+
.sess
1045+
.emit_err(errors::ConstVectorEvaluation { span: constant.span });
1046+
// We've errored, so we don't have to produce working code.
1047+
let llty = bx.backend_type(bx.layout_of(ty));
1048+
bx.const_undef(llty)
1049+
});
1050+
OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) }
1051+
} else {
1052+
span_bug!(span, "argument at {i} must be a constant vector");
1053+
}
1054+
} else {
1055+
self.codegen_operand(bx, &arg.node)
1056+
};
10091057

10101058
if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, def) {
10111059
match op.val {

compiler/rustc_codegen_ssa/src/mir/constant.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::errors;
21
use crate::mir::operand::OperandRef;
32
use crate::traits::*;
43
use rustc_middle::mir;
@@ -29,7 +28,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2928
.expect("erroneous constant missed by mono item collection")
3029
}
3130

32-
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
31+
/// This is a convenience helper for `early_evaluate_const_vector`. It has the precondition
3332
/// that the given `constant` is an `Const::Unevaluated` and must be convertible to
3433
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
3534
///
@@ -60,12 +59,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
6059
self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span)
6160
}
6261

63-
/// process constant containing SIMD shuffle indices
64-
pub fn simd_shuffle_indices(
62+
/// process constant SIMD vector or constant containing SIMD shuffle indices
63+
pub fn early_evaluate_const_vector(
6564
&mut self,
6665
bx: &Bx,
6766
constant: &mir::ConstOperand<'tcx>,
68-
) -> (Bx::Value, Ty<'tcx>) {
67+
) -> (Option<Bx::Value>, Ty<'tcx>) {
6968
let ty = self.monomorphize(constant.ty());
7069
let val = self
7170
.eval_unevaluated_mir_constant_to_valtree(constant)
@@ -85,17 +84,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
8584
};
8685
bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
8786
} else {
88-
bug!("simd shuffle field {:?}", field)
87+
bug!("field is not a scalar {:?}", field)
8988
}
9089
})
9190
.collect();
92-
bx.const_struct(&values, false)
93-
})
94-
.unwrap_or_else(|| {
95-
bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });
96-
// We've errored, so we don't have to produce working code.
97-
let llty = bx.backend_type(bx.layout_of(ty));
98-
bx.const_undef(llty)
91+
if ty.is_simd() {
92+
bx.const_vector(&values)
93+
} else {
94+
bx.const_struct(&values, false)
95+
}
9996
});
10097
(val, ty)
10198
}

compiler/rustc_codegen_ssa/src/traits/consts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
2929

3030
fn const_str(&self, s: &str) -> (Self::Value, Self::Value);
3131
fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
32+
fn const_vector(&self, elts: &[Self::Value]) -> Self::Value;
3233

3334
fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
3435
fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;

compiler/rustc_feature/src/builtin_attrs.rs

+3
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
837837
rustc_runtime, Normal, template!(Word), WarnFollowing,
838838
EncodeCrossCrate::No, INTERNAL_UNSTABLE
839839
),
840+
rustc_attr!(
841+
rustc_intrinsic_const_vector_arg, Normal, template!(List: "arg1_index, arg2_index, ..."), ErrorFollowing, INTERNAL_UNSTABLE
842+
),
840843

841844
// ==========================================================================
842845
// Internal attributes, Layout related:

compiler/rustc_passes/messages.ftl

+12
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,18 @@ passes_rustc_allow_const_fn_unstable =
601601
passes_rustc_dirty_clean =
602602
attribute requires -Z query-dep-graph to be enabled
603603
604+
passes_rustc_intrinsic_const_vector_arg =
605+
attribute should be applied to functions in `extern "unadjusted"` modules
606+
.label = not a function in an `extern "unadjusted"` module
607+
608+
passes_rustc_intrinsic_const_vector_arg_invalid = attribute requires a parameter index
609+
610+
passes_rustc_intrinsic_const_vector_arg_non_vector = parameter at index {$index} must be a simd type
611+
.label = parameter is a non-simd type
612+
613+
passes_rustc_intrinsic_const_vector_arg_out_of_bounds = function does not have a parameter at index {$index}
614+
.label = function has {$arg_count} arguments
615+
604616
passes_rustc_layout_scalar_valid_range_arg =
605617
expected exactly one integer literal argument
606618

0 commit comments

Comments
 (0)