Skip to content

Commit 8769ef6

Browse files
committed
light touch implementation of const vector
1 parent e60ebb2 commit 8769ef6

File tree

7 files changed

+121
-12
lines changed

7 files changed

+121
-12
lines changed

compiler/rustc_codegen_gcc/src/common.rs

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

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

compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 4 additions & 0 deletions
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/src/mir/block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
924924
// checked by the type-checker.
925925
if i == 2 && intrinsic.name == sym::simd_shuffle {
926926
if let mir::Operand::Constant(constant) = &arg.node {
927-
let (llval, ty) = self.simd_shuffle_indices(bx, constant);
927+
let (llval, ty) = self.immediate_const_vector(bx, constant);
928928
return OperandRef {
929929
val: Immediate(llval),
930930
layout: bx.layout_of(ty),

compiler/rustc_codegen_ssa/src/mir/constant.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_middle::mir::interpret::ErrorHandled;
22
use rustc_middle::ty::layout::HasTyCtxt;
3-
use rustc_middle::ty::{self, Ty};
3+
use rustc_middle::ty::{self, Ty, ValTree};
44
use rustc_middle::{bug, mir, span_bug};
55
use rustc_target::abi::Abi;
66

@@ -28,7 +28,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2828
.expect("erroneous constant missed by mono item collection")
2929
}
3030

31-
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
31+
/// This is a convenience helper for `immediate_const_vector`. It has the precondition
3232
/// that the given `constant` is an `Const::Unevaluated` and must be convertible to
3333
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
3434
///
@@ -59,23 +59,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
5959
self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span)
6060
}
6161

62-
/// process constant containing SIMD shuffle indices
63-
pub fn simd_shuffle_indices(
62+
/// process constant containing SIMD shuffle indices & constant vectors
63+
pub fn immediate_const_vector(
6464
&mut self,
6565
bx: &Bx,
6666
constant: &mir::ConstOperand<'tcx>,
6767
) -> (Bx::Value, Ty<'tcx>) {
6868
let ty = self.monomorphize(constant.ty());
69+
let ty_is_simd = ty.is_simd();
70+
let field_ty = if ty_is_simd {
71+
ty.simd_size_and_type(bx.tcx()).1
72+
} else {
73+
ty.builtin_index().unwrap()
74+
};
75+
6976
let val = self
7077
.eval_unevaluated_mir_constant_to_valtree(constant)
7178
.ok()
7279
.map(|x| x.ok())
7380
.flatten()
7481
.map(|val| {
75-
let field_ty = ty.builtin_index().unwrap();
76-
let values: Vec<_> = val
77-
.unwrap_branch()
78-
.iter()
82+
let field_iter = val.unwrap_branch();
83+
let first = field_iter.get(0).unwrap();
84+
let field_iter = match first {
85+
ValTree::Branch(_) => first.unwrap_branch().iter(),
86+
ValTree::Leaf(_) => field_iter.iter(),
87+
};
88+
let values: Vec<_> = field_iter
7989
.map(|field| {
8090
if let Some(prim) = field.try_to_scalar() {
8191
let layout = bx.layout_of(field_ty);
@@ -84,11 +94,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
8494
};
8595
bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
8696
} else {
87-
bug!("simd shuffle field {:?}", field)
97+
bug!("field is not a scalar {:?}", field)
8898
}
8999
})
90100
.collect();
91-
bx.const_struct(&values, false)
101+
if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) }
92102
})
93103
.unwrap_or_else(|| {
94104
bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
635635
self.codegen_consume(bx, place.as_ref())
636636
}
637637

638-
mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
638+
mir::Operand::Constant(ref constant) => {
639+
if constant.ty().is_simd() {
640+
let (llval, ty) = self.immediate_const_vector(bx, constant);
641+
OperandRef { val: OperandValue::Immediate(llval), layout: bx.layout_of(ty) }
642+
} else {
643+
self.eval_mir_constant_to_operand(bx, constant)
644+
}
645+
}
639646
}
640647
}
641648
}

compiler/rustc_codegen_ssa/src/traits/consts.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
3030

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

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

tests/codegen/const-vector.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
2+
3+
// Ensuring the 2 different ways of creating const vectors works
4+
#![crate_type = "lib"]
5+
#![feature(abi_unadjusted)]
6+
#![allow(non_camel_case_types)]
7+
#![feature(const_trait_impl)]
8+
#![feature(repr_simd)]
9+
#![feature(rustc_attrs)]
10+
#![feature(simd_ffi)]
11+
12+
// Setting up structs that can be used as const vectors
13+
#[repr(simd)]
14+
#[derive(Clone)]
15+
pub struct i8x2(i8, i8);
16+
17+
#[repr(simd)]
18+
#[derive(Clone)]
19+
pub struct i8x2_arr([i8; 2]);
20+
21+
#[repr(simd)]
22+
#[derive(Clone)]
23+
pub struct f32x2(f32, f32);
24+
25+
#[repr(simd)]
26+
#[derive(Clone)]
27+
pub struct f32x2_arr([f32; 2]);
28+
29+
// The following functions are required for the tests to ensure
30+
// that they are called with a const vector
31+
32+
extern "unadjusted" {
33+
#[no_mangle]
34+
fn test_i8x2(a: i8x2);
35+
}
36+
37+
extern "unadjusted" {
38+
#[no_mangle]
39+
fn test_i8x2_two_args(a: i8x2, b: i8x2);
40+
}
41+
42+
extern "unadjusted" {
43+
#[no_mangle]
44+
fn test_i8x2_mixed_args(a: i8x2, c: i32, b: i8x2);
45+
}
46+
47+
extern "unadjusted" {
48+
#[no_mangle]
49+
fn test_i8x2_arr(a: i8x2_arr);
50+
}
51+
52+
extern "unadjusted" {
53+
#[no_mangle]
54+
fn test_f32x2(a: f32x2);
55+
}
56+
57+
extern "unadjusted" {
58+
#[no_mangle]
59+
fn test_f32x2_arr(a: f32x2_arr);
60+
}
61+
62+
pub fn do_call() {
63+
unsafe {
64+
// CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64>
65+
test_i8x2(const { i8x2(32, 64) });
66+
67+
// CHECK: call void @test_i8x2_two_args(<2 x i8> <i8 32, i8 64>, <2 x i8> <i8 8, i8 16>
68+
test_i8x2_two_args(const { i8x2(32, 64) }, const { i8x2(8, 16) });
69+
70+
// CHECK: call void @test_i8x2_mixed_args(<2 x i8> <i8 32, i8 64>, i32 43, <2 x i8> <i8 8, i8 16>
71+
test_i8x2_mixed_args(const { i8x2(32, 64) }, 43, const {i8x2(8, 16) });
72+
73+
// CHECK: call void @test_i8x2_arr(<2 x i8> <i8 32, i8 64>
74+
test_i8x2_arr(const { i8x2_arr([32, 64]) });
75+
76+
// CHECK: call void @test_f32x2(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
77+
test_f32x2(const { f32x2(0.32, 0.64) });
78+
79+
// CHECK: void @test_f32x2_arr(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
80+
test_f32x2_arr(const { f32x2_arr([0.32, 0.64]) });
81+
}
82+
}

0 commit comments

Comments
 (0)