Build StKind::CopyOverlapping
This replaces where it was previously being constructed in intrinsics, with direct construction of the Statement.
This commit is contained in:
parent
845e4b5962
commit
d4ae9ff826
5 changed files with 100 additions and 77 deletions
|
@ -837,10 +837,21 @@ fn codegen_stmt<'tcx>(
|
||||||
dst,
|
dst,
|
||||||
count,
|
count,
|
||||||
}) => {
|
}) => {
|
||||||
let dst = codegen_operand(fx, dst).load_scalar(fx);
|
let dst = codegen_operand(fx, dst);
|
||||||
|
let pointee = dst
|
||||||
|
.layout()
|
||||||
|
.pointee_info_at(fx, rustc_target::abi::Size::ZERO)
|
||||||
|
.expect("Expected pointer");
|
||||||
|
let dst = dst.load_scalar(fx);
|
||||||
let src = codegen_operand(fx, src).load_scalar(fx);
|
let src = codegen_operand(fx, src).load_scalar(fx);
|
||||||
let count = codegen_operand(fx, count).load_scalar(fx);
|
let count = codegen_operand(fx, count).load_scalar(fx);
|
||||||
fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, count);
|
let elem_size: u64 = pointee.size.bytes();
|
||||||
|
let bytes = if elem_size != 1 {
|
||||||
|
fx.bcx.ins().imul_imm(count, elem_size as i64)
|
||||||
|
} else {
|
||||||
|
count
|
||||||
|
};
|
||||||
|
fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#![feature(or_patterns)]
|
#![feature(or_patterns)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
#![feature(box_syntax)]
|
||||||
|
|
||||||
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
|
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
|
||||||
//! The backend-agnostic functions of this crate use functions defined in various traits that
|
//! The backend-agnostic functions of this crate use functions defined in various traits that
|
||||||
|
|
|
@ -641,67 +641,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if intrinsic.is_some() && intrinsic != Some(sym::drop_in_place) {
|
match intrinsic {
|
||||||
let intrinsic = intrinsic.unwrap();
|
None | Some(sym::drop_in_place) => {}
|
||||||
let dest = match ret_dest {
|
Some(sym::copy_nonoverlapping) => {
|
||||||
_ if fn_abi.ret.is_indirect() => llargs[0],
|
bx = self.codegen_statement(
|
||||||
ReturnDest::Nothing => {
|
bx,
|
||||||
bx.const_undef(bx.type_ptr_to(bx.arg_memory_ty(&fn_abi.ret)))
|
&rustc_middle::mir::Statement {
|
||||||
}
|
source_info: rustc_middle::mir::SourceInfo::outermost(span),
|
||||||
ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval,
|
kind: rustc_middle::mir::StatementKind::CopyNonOverlapping(
|
||||||
ReturnDest::DirectOperand(_) => {
|
box rustc_middle::mir::CopyNonOverlapping {
|
||||||
bug!("Cannot use direct operand with an intrinsic call")
|
src: args[0].clone(),
|
||||||
}
|
dst: args[1].clone(),
|
||||||
};
|
count: args[2].clone(),
|
||||||
|
},
|
||||||
let args: Vec<_> = args
|
),
|
||||||
.iter()
|
},
|
||||||
.enumerate()
|
);
|
||||||
.map(|(i, arg)| {
|
helper.funclet_br(self, &mut bx, destination.unwrap().1);
|
||||||
// The indices passed to simd_shuffle* in the
|
return;
|
||||||
// third argument must be constant. This is
|
}
|
||||||
// checked by const-qualification, which also
|
Some(intrinsic) => {
|
||||||
// promotes any complex rvalues to constants.
|
let dest = match ret_dest {
|
||||||
if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
|
_ if fn_abi.ret.is_indirect() => llargs[0],
|
||||||
if let mir::Operand::Constant(constant) = arg {
|
ReturnDest::Nothing => {
|
||||||
let c = self.eval_mir_constant(constant);
|
bx.const_undef(bx.type_ptr_to(bx.arg_memory_ty(&fn_abi.ret)))
|
||||||
let (llval, ty) = self.simd_shuffle_indices(
|
|
||||||
&bx,
|
|
||||||
constant.span,
|
|
||||||
constant.literal.ty,
|
|
||||||
c,
|
|
||||||
);
|
|
||||||
return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) };
|
|
||||||
} else {
|
|
||||||
span_bug!(span, "shuffle indices must be constant");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.llval,
|
||||||
|
ReturnDest::DirectOperand(_) => {
|
||||||
|
bug!("Cannot use direct operand with an intrinsic call")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.codegen_operand(&mut bx, arg)
|
let args: Vec<_> = args
|
||||||
})
|
.iter()
|
||||||
.collect();
|
.enumerate()
|
||||||
|
.map(|(i, arg)| {
|
||||||
|
// 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 i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
|
||||||
|
if let mir::Operand::Constant(constant) = arg {
|
||||||
|
let c = self.eval_mir_constant(constant);
|
||||||
|
let (llval, ty) = self.simd_shuffle_indices(
|
||||||
|
&bx,
|
||||||
|
constant.span,
|
||||||
|
constant.literal.ty,
|
||||||
|
c,
|
||||||
|
);
|
||||||
|
return OperandRef {
|
||||||
|
val: Immediate(llval),
|
||||||
|
layout: bx.layout_of(ty),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
span_bug!(span, "shuffle indices must be constant");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Self::codegen_intrinsic_call(
|
self.codegen_operand(&mut bx, arg)
|
||||||
&mut bx,
|
})
|
||||||
*instance.as_ref().unwrap(),
|
.collect();
|
||||||
&fn_abi,
|
|
||||||
&args,
|
|
||||||
dest,
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
|
self.codegen_intrinsic_call(
|
||||||
self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval);
|
&mut bx,
|
||||||
|
*instance.as_ref().unwrap(),
|
||||||
|
&fn_abi,
|
||||||
|
&args,
|
||||||
|
dest,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
|
||||||
|
self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_, target)) = *destination {
|
||||||
|
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
|
||||||
|
helper.funclet_br(self, &mut bx, target);
|
||||||
|
} else {
|
||||||
|
bx.unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((_, target)) = *destination {
|
|
||||||
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
|
|
||||||
helper.funclet_br(self, &mut bx, target);
|
|
||||||
} else {
|
|
||||||
bx.unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split the rust-call tupled arguments off.
|
// Split the rust-call tupled arguments off.
|
||||||
|
|
|
@ -49,6 +49,7 @@ fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
|
|
||||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
pub fn codegen_intrinsic_call(
|
pub fn codegen_intrinsic_call(
|
||||||
|
&self,
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||||
|
@ -127,16 +128,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
sym::copy_nonoverlapping => {
|
sym::copy_nonoverlapping => {
|
||||||
copy_intrinsic(
|
// handled explicitly in compiler/rustc_codegen_ssa/src/mir/block.rs
|
||||||
bx,
|
unreachable!();
|
||||||
false,
|
|
||||||
false,
|
|
||||||
substs.type_at(0),
|
|
||||||
args[1].immediate(),
|
|
||||||
args[0].immediate(),
|
|
||||||
args[2].immediate(),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
sym::copy => {
|
sym::copy => {
|
||||||
copy_intrinsic(
|
copy_intrinsic(
|
||||||
|
|
|
@ -123,20 +123,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let dst_val = self.codegen_operand(&mut bx, dst);
|
let dst_val = self.codegen_operand(&mut bx, dst);
|
||||||
let src_val = self.codegen_operand(&mut bx, src);
|
let src_val = self.codegen_operand(&mut bx, src);
|
||||||
let count = self.codegen_operand(&mut bx, count).immediate();
|
let count = self.codegen_operand(&mut bx, count).immediate();
|
||||||
let get_val_align = |oper_ref: crate::mir::OperandRef<'_, _>| match oper_ref.val {
|
|
||||||
OperandValue::Ref(val, _, align) => (val, align),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let pointee_layout = dst_val
|
let pointee_layout = dst_val
|
||||||
.layout
|
.layout
|
||||||
.pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
|
.pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
|
||||||
.expect("Expected pointer");
|
.expect("Expected pointer");
|
||||||
let elem_size = bx.const_u64(pointee_layout.size.bytes());
|
let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes()));
|
||||||
let byte_count = bx.mul(count, elem_size);
|
|
||||||
|
|
||||||
let (dst, dst_align) = get_val_align(dst_val);
|
let align = pointee_layout.align;
|
||||||
let (src, src_align) = get_val_align(src_val);
|
let dst = dst_val.immediate();
|
||||||
bx.memcpy(dst, dst_align, src, src_align, byte_count, crate::MemFlags::empty());
|
let src = src_val.immediate();
|
||||||
|
bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty());
|
||||||
bx
|
bx
|
||||||
}
|
}
|
||||||
mir::StatementKind::FakeRead(..)
|
mir::StatementKind::FakeRead(..)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue