trans: support simd_shuffle using MIR constants for indices.
This commit is contained in:
parent
ed66fe48e9
commit
5c42e694cb
5 changed files with 51 additions and 45 deletions
|
@ -1482,28 +1482,23 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
|
|||
|
||||
let total_len = in_len as u64 * 2;
|
||||
|
||||
let (vector, indirect) = match args {
|
||||
let vector = match args {
|
||||
Some(args) => {
|
||||
match consts::const_expr(bcx.ccx(), &args[2], substs, None,
|
||||
// this should probably help simd error reporting
|
||||
consts::TrueConst::Yes) {
|
||||
Ok((vector, _)) => (vector, false),
|
||||
Ok((vector, _)) => vector,
|
||||
Err(err) => bcx.sess().span_fatal(span, &err.description()),
|
||||
}
|
||||
}
|
||||
None => (llargs[2], !type_is_immediate(bcx.ccx(), arg_tys[2]))
|
||||
None => llargs[2]
|
||||
};
|
||||
|
||||
let indices: Option<Vec<_>> = (0..n)
|
||||
.map(|i| {
|
||||
let arg_idx = i;
|
||||
let val = if indirect {
|
||||
Load(bcx, StructGEP(bcx, vector, i))
|
||||
} else {
|
||||
const_get_elt(vector, &[i as libc::c_uint])
|
||||
};
|
||||
let c = const_to_opt_uint(val);
|
||||
match c {
|
||||
let val = const_get_elt(vector, &[i as libc::c_uint]);
|
||||
match const_to_opt_uint(val) {
|
||||
None => {
|
||||
emit_error!("shuffle index #{} is not a constant", arg_idx);
|
||||
None
|
||||
|
|
|
@ -26,6 +26,7 @@ use glue;
|
|||
use type_::Type;
|
||||
|
||||
use super::{MirContext, TempRef, drop};
|
||||
use super::constant::Const;
|
||||
use super::lvalue::{LvalueRef, load_fat_ptr};
|
||||
use super::operand::OperandRef;
|
||||
use super::operand::OperandValue::{self, FatPtr, Immediate, Ref};
|
||||
|
@ -114,16 +115,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
let discr = bcx.with_block(|bcx| base::to_immediate(bcx, discr, switch_ty));
|
||||
let switch = bcx.switch(discr, self.llblock(*otherwise), values.len());
|
||||
for (value, target) in values.iter().zip(targets) {
|
||||
let constant = mir::Constant {
|
||||
literal: mir::Literal::Value {
|
||||
value: value.clone()
|
||||
},
|
||||
ty: switch_ty,
|
||||
span: terminator.span
|
||||
};
|
||||
let val = self.trans_constant(&bcx, &constant).immediate();
|
||||
let val = Const::from_constval(bcx.ccx(), value.clone(), switch_ty);
|
||||
let llbb = self.llblock(*target);
|
||||
build::AddCase(switch, val, llbb)
|
||||
build::AddCase(switch, val.llval, llbb)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,8 +241,30 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
(&args[..], None)
|
||||
};
|
||||
|
||||
let is_shuffle = intrinsic.map_or(false, |name| {
|
||||
name.starts_with("simd_shuffle")
|
||||
});
|
||||
let mut idx = 0;
|
||||
for arg in first_args {
|
||||
// The indices passed to simd_shuffle* in the
|
||||
// third argument must be constant. This is
|
||||
// checked by const-qualification, which also
|
||||
// promotes any complex rvalues to constants.
|
||||
if is_shuffle && idx == 2 {
|
||||
match *arg {
|
||||
mir::Operand::Consume(_) => {
|
||||
span_bug!(terminator.span,
|
||||
"shuffle indices must be constant");
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
let val = self.trans_constant(&bcx, constant);
|
||||
llargs.push(val.llval);
|
||||
idx += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let val = self.trans_operand(&bcx, arg).val;
|
||||
self.trans_argument(&bcx, val, &mut llargs, &fn_ty,
|
||||
&mut idx, &mut callee.data);
|
||||
|
|
|
@ -41,13 +41,13 @@ use super::MirContext;
|
|||
/// The LLVM type might not be the same for a single Rust type,
|
||||
/// e.g. each enum variant would have its own LLVM struct type.
|
||||
#[derive(Copy, Clone)]
|
||||
struct Const<'tcx> {
|
||||
llval: ValueRef,
|
||||
ty: Ty<'tcx>
|
||||
pub struct Const<'tcx> {
|
||||
pub llval: ValueRef,
|
||||
pub ty: Ty<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
Const {
|
||||
llval: llval,
|
||||
ty: ty
|
||||
|
@ -55,10 +55,10 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
/// Translate ConstVal into a LLVM constant value.
|
||||
fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
cv: ConstVal,
|
||||
ty: Ty<'tcx>)
|
||||
-> Const<'tcx> {
|
||||
pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
cv: ConstVal,
|
||||
ty: Ty<'tcx>)
|
||||
-> Const<'tcx> {
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
let val = match cv {
|
||||
ConstVal::Float(v) => C_floating_f64(v, llty),
|
||||
|
@ -110,7 +110,7 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
|
||||
pub fn to_operand<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
|
||||
let llty = type_of::immediate_type_of(ccx, self.ty);
|
||||
let llvalty = val_ty(self.llval);
|
||||
|
||||
|
@ -799,7 +799,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
pub fn trans_constant(&mut self,
|
||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||
constant: &mir::Constant<'tcx>)
|
||||
-> OperandRef<'tcx>
|
||||
-> Const<'tcx>
|
||||
{
|
||||
let ty = bcx.monomorphize(&constant.ty);
|
||||
let result = match constant.literal.clone() {
|
||||
|
@ -808,10 +808,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
// types, which would not work with MirConstContext.
|
||||
if common::type_is_zero_size(bcx.ccx(), ty) {
|
||||
let llty = type_of::type_of(bcx.ccx(), ty);
|
||||
return OperandRef {
|
||||
val: OperandValue::Immediate(C_null(llty)),
|
||||
ty: ty
|
||||
};
|
||||
return Const::new(C_null(llty), ty);
|
||||
}
|
||||
|
||||
let substs = bcx.tcx().mk_substs(bcx.monomorphize(substs));
|
||||
|
@ -827,7 +824,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let val = match result {
|
||||
match result {
|
||||
Ok(v) => v,
|
||||
Err(ConstEvalFailure::Compiletime(_)) => {
|
||||
// We've errored, so we don't have to produce working code.
|
||||
|
@ -839,14 +836,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
"MIR constant {:?} results in runtime panic: {}",
|
||||
constant, err.description())
|
||||
}
|
||||
};
|
||||
|
||||
let operand = val.to_operand(bcx.ccx());
|
||||
if let OperandValue::Ref(ptr) = operand.val {
|
||||
// If this is a OperandValue::Ref to an immediate constant, load it.
|
||||
self.trans_load(bcx, ptr, operand.ty)
|
||||
} else {
|
||||
operand
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
self.trans_constant(bcx, constant)
|
||||
let val = self.trans_constant(bcx, constant);
|
||||
let operand = val.to_operand(bcx.ccx());
|
||||
if let OperandValue::Ref(ptr) = operand.val {
|
||||
// If this is a OperandValue::Ref to an immediate constant, load it.
|
||||
self.trans_load(bcx, ptr, operand.ty)
|
||||
} else {
|
||||
operand
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(repr_simd, rustc_attrs, platform_intrinsics)]
|
||||
#![feature(repr_simd, platform_intrinsics)]
|
||||
|
||||
// ignore-pretty : (#23623) problems when ending with // comments
|
||||
|
||||
|
@ -52,7 +52,6 @@ macro_rules! all_eq {
|
|||
}}
|
||||
}
|
||||
|
||||
#[rustc_no_mir] // FIXME #27840 MIR doesn't handle shuffle constants.
|
||||
fn main() {
|
||||
let x2 = i32x2(20, 21);
|
||||
let x3 = i32x3(30, 31, 32);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue