Skip to content

Commit

Permalink
trans: support simd_shuffle using MIR constants for indices.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed May 7, 2016
1 parent ed66fe4 commit 5c42e69
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 45 deletions.
15 changes: 5 additions & 10 deletions src/librustc_trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 25 additions & 9 deletions src/librustc_trans/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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);
Expand Down
35 changes: 12 additions & 23 deletions src/librustc_trans/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,24 @@ 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
}
}

/// 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),
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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() {
Expand All @@ -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));
Expand All @@ -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.
Expand All @@ -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
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/librustc_trans/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/test/run-pass/simd-intrinsic-generic-elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 5c42e69

Please sign in to comment.