Traitified IntrinsicCallMethods
This commit is contained in:
parent
a5aeb8edd6
commit
0a1c50955b
11 changed files with 670 additions and 646 deletions
|
@ -73,9 +73,7 @@ use rustc_data_structures::small_c_str::SmallCStr;
|
|||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use interfaces::{
|
||||
BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
|
||||
};
|
||||
use interfaces::*;
|
||||
|
||||
use std::any::Any;
|
||||
use std::cmp;
|
||||
|
|
|
@ -19,10 +19,7 @@ use rustc::ty::TyCtxt;
|
|||
use rustc::ty::layout::{Align, Size};
|
||||
use rustc::session::{config, Session};
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use interfaces::{
|
||||
Backend,
|
||||
BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
|
||||
};
|
||||
use interfaces::*;
|
||||
use syntax;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -59,16 +56,11 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
impl Backend for Builder<'a, 'll, 'tcx> {
|
||||
type Value = &'ll Value;
|
||||
type BasicBlock = &'ll BasicBlock;
|
||||
type Type = &'ll Type;
|
||||
type Context = &'ll llvm::Context;
|
||||
impl HasCodegen for Builder<'a, 'll, 'tcx> {
|
||||
type CodegenCx = CodegenCx<'ll, 'tcx>;
|
||||
}
|
||||
|
||||
impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
type CodegenCx = CodegenCx<'ll, 'tcx>;
|
||||
|
||||
fn new_block<'b>(
|
||||
cx: &'a CodegenCx<'ll, 'tcx>,
|
||||
llfn: &'ll Value,
|
||||
|
|
|
@ -23,8 +23,7 @@ use value::Value;
|
|||
use monomorphize::partitioning::CodegenUnit;
|
||||
use type_::Type;
|
||||
use type_of::PointeeInfo;
|
||||
use interfaces::{BaseTypeMethods, DerivedTypeMethods,
|
||||
IntrinsicMethods, BaseIntrinsicMethods, DerivedIntrinsicMethods};
|
||||
use interfaces::{BaseTypeMethods, DerivedTypeMethods, IntrinsicDeclarationMethods};
|
||||
|
||||
use rustc_data_structures::base_n;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
|
@ -323,9 +322,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl BaseIntrinsicMethods for CodegenCx<'_, '_> {}
|
||||
|
||||
impl DerivedIntrinsicMethods for CodegenCx<'b, 'tcx> {
|
||||
impl IntrinsicDeclarationMethods for CodegenCx<'b, 'tcx> {
|
||||
fn get_intrinsic(&self, key: &str) -> &'b Value {
|
||||
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
|
||||
return v;
|
||||
|
@ -647,8 +644,6 @@ impl DerivedIntrinsicMethods for CodegenCx<'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntrinsicMethods for CodegenCx<'a, 'tcx> {}
|
||||
|
||||
impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
|
||||
/// Generate a new symbol name with the given prefix. This symbol name must
|
||||
/// only be used for definitions with `internal` or `private` linkage.
|
||||
|
|
|
@ -17,21 +17,29 @@ use builder::MemFlags;
|
|||
use super::backend::Backend;
|
||||
use super::type_::TypeMethods;
|
||||
use super::consts::ConstMethods;
|
||||
use super::intrinsic::IntrinsicMethods;
|
||||
use super::intrinsic::IntrinsicDeclarationMethods;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Range;
|
||||
use syntax::ast::AsmDialect;
|
||||
|
||||
|
||||
pub trait BuilderMethods<'a, 'tcx: 'a>: Backend {
|
||||
type CodegenCx: 'a + TypeMethods + ConstMethods + IntrinsicMethods + Backend<
|
||||
pub trait HasCodegen: Backend {
|
||||
type CodegenCx: TypeMethods + ConstMethods + IntrinsicDeclarationMethods + Backend<
|
||||
Value = Self::Value,
|
||||
BasicBlock = Self::BasicBlock,
|
||||
Type = Self::Type,
|
||||
Context = Self::Context,
|
||||
>;
|
||||
}
|
||||
|
||||
impl<T: HasCodegen> Backend for T {
|
||||
type Value = <T::CodegenCx as Backend>::Value;
|
||||
type BasicBlock = <T::CodegenCx as Backend>::BasicBlock;
|
||||
type Type = <T::CodegenCx as Backend>::Type;
|
||||
type Context = <T::CodegenCx as Backend>::Context;
|
||||
}
|
||||
|
||||
pub trait BuilderMethods<'a, 'tcx: 'a>: HasCodegen {
|
||||
fn new_block<'b>(
|
||||
cx: &'a Self::CodegenCx,
|
||||
llfn: Self::Value,
|
||||
|
|
|
@ -9,17 +9,27 @@
|
|||
// except according to those terms.
|
||||
|
||||
use super::backend::Backend;
|
||||
use super::builder::HasCodegen;
|
||||
use mir::operand::OperandRef;
|
||||
use rustc::ty::Ty;
|
||||
use abi::FnType;
|
||||
use syntax_pos::Span;
|
||||
|
||||
pub trait BaseIntrinsicMethods: Backend {
|
||||
|
||||
pub trait IntrinsicCallMethods<'a, 'tcx: 'a>: HasCodegen {
|
||||
fn codegen_intrinsic_call(
|
||||
&self,
|
||||
callee_ty: Ty<'tcx>,
|
||||
fn_ty: &FnType<'tcx, Ty<'tcx>>,
|
||||
args: &[OperandRef<'tcx, Self::Value>],
|
||||
llresult: Self::Value,
|
||||
span: Span,
|
||||
);
|
||||
}
|
||||
|
||||
pub trait DerivedIntrinsicMethods: Backend {
|
||||
pub trait IntrinsicDeclarationMethods: Backend {
|
||||
fn get_intrinsic(&self, key: &str) -> Self::Value;
|
||||
fn declare_intrinsic(
|
||||
&self,
|
||||
key: &str
|
||||
) -> Option<Self::Value>;
|
||||
}
|
||||
|
||||
pub trait IntrinsicMethods: BaseIntrinsicMethods + DerivedIntrinsicMethods {}
|
||||
|
|
|
@ -15,9 +15,9 @@ mod type_;
|
|||
mod intrinsic;
|
||||
mod statics;
|
||||
|
||||
pub use self::builder::BuilderMethods;
|
||||
pub use self::builder::{BuilderMethods, HasCodegen};
|
||||
pub use self::backend::Backend;
|
||||
pub use self::consts::ConstMethods;
|
||||
pub use self::type_::{TypeMethods, BaseTypeMethods, DerivedTypeMethods};
|
||||
pub use self::intrinsic::{IntrinsicMethods, BaseIntrinsicMethods, DerivedIntrinsicMethods};
|
||||
pub use self::intrinsic::{IntrinsicCallMethods, IntrinsicDeclarationMethods};
|
||||
pub use self::statics::StaticMethods;
|
||||
|
|
|
@ -32,10 +32,7 @@ use syntax::symbol::Symbol;
|
|||
use builder::{Builder, MemFlags};
|
||||
use value::Value;
|
||||
|
||||
use interfaces::{
|
||||
BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
|
||||
StaticMethods,
|
||||
};
|
||||
use interfaces::*;
|
||||
|
||||
use rustc::session::Session;
|
||||
use syntax_pos::Span;
|
||||
|
@ -90,18 +87,19 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu
|
|||
Some(cx.get_intrinsic(&llvm_name))
|
||||
}
|
||||
|
||||
/// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs,
|
||||
/// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics,
|
||||
/// add them to librustc_codegen_llvm/context.rs
|
||||
pub fn codegen_intrinsic_call(
|
||||
bx: &Builder<'a, 'll, 'tcx>,
|
||||
impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||
/// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs,
|
||||
/// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics,
|
||||
/// add them to librustc_codegen_llvm/context.rs
|
||||
fn codegen_intrinsic_call(
|
||||
&self,
|
||||
callee_ty: Ty<'tcx>,
|
||||
fn_ty: &FnType<'tcx, Ty<'tcx>>,
|
||||
args: &[OperandRef<'tcx, &'ll Value>],
|
||||
llresult: &'ll Value,
|
||||
span: Span,
|
||||
) {
|
||||
let cx = bx.cx();
|
||||
) {
|
||||
let cx = self.cx();
|
||||
let tcx = cx.tcx;
|
||||
|
||||
let (def_id, substs) = match callee_ty.sty {
|
||||
|
@ -121,7 +119,7 @@ pub fn codegen_intrinsic_call(
|
|||
let simple = get_simple_intrinsic(cx, name);
|
||||
let llval = match name {
|
||||
_ if simple.is_some() => {
|
||||
bx.call(simple.unwrap(),
|
||||
self.call(simple.unwrap(),
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
None)
|
||||
}
|
||||
|
@ -130,14 +128,14 @@ pub fn codegen_intrinsic_call(
|
|||
},
|
||||
"likely" => {
|
||||
let expect = cx.get_intrinsic(&("llvm.expect.i1"));
|
||||
bx.call(expect, &[args[0].immediate(), bx.cx().const_bool(true)], None)
|
||||
self.call(expect, &[args[0].immediate(), cx.const_bool(true)], None)
|
||||
}
|
||||
"unlikely" => {
|
||||
let expect = cx.get_intrinsic(&("llvm.expect.i1"));
|
||||
bx.call(expect, &[args[0].immediate(), bx.cx().const_bool(false)], None)
|
||||
self.call(expect, &[args[0].immediate(), cx.const_bool(false)], None)
|
||||
}
|
||||
"try" => {
|
||||
try_intrinsic(bx, cx,
|
||||
try_intrinsic(self, cx,
|
||||
args[0].immediate(),
|
||||
args[1].immediate(),
|
||||
args[2].immediate(),
|
||||
|
@ -146,7 +144,7 @@ pub fn codegen_intrinsic_call(
|
|||
}
|
||||
"breakpoint" => {
|
||||
let llfn = cx.get_intrinsic(&("llvm.debugtrap"));
|
||||
bx.call(llfn, &[], None)
|
||||
self.call(llfn, &[], None)
|
||||
}
|
||||
"size_of" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
|
@ -156,7 +154,7 @@ pub fn codegen_intrinsic_call(
|
|||
let tp_ty = substs.type_at(0);
|
||||
if let OperandValue::Pair(_, meta) = args[0].val {
|
||||
let (llsize, _) =
|
||||
glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
|
||||
glue::size_and_align_of_dst(&self, tp_ty, Some(meta));
|
||||
llsize
|
||||
} else {
|
||||
cx.const_usize(cx.size_of(tp_ty).bytes())
|
||||
|
@ -170,7 +168,7 @@ pub fn codegen_intrinsic_call(
|
|||
let tp_ty = substs.type_at(0);
|
||||
if let OperandValue::Pair(_, meta) = args[0].val {
|
||||
let (_, llalign) =
|
||||
glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
|
||||
glue::size_and_align_of_dst(&self, tp_ty, Some(meta));
|
||||
llalign
|
||||
} else {
|
||||
cx.const_usize(cx.align_of(tp_ty).abi())
|
||||
|
@ -192,11 +190,11 @@ pub fn codegen_intrinsic_call(
|
|||
let ty = substs.type_at(0);
|
||||
if !cx.layout_of(ty).is_zst() {
|
||||
// Just zero out the stack slot.
|
||||
// If we store a zero constant, LLVM will drown in vreg allocation for large data
|
||||
// structures, and the generated code will be awful. (A telltale sign of this is
|
||||
// large quantities of `mov [byte ptr foo],0` in the generated code.)
|
||||
// If we store a zero constant, LLVM will drown in vreg allocation for large
|
||||
// data structures, and the generated code will be awful. (A telltale sign of
|
||||
// this is large quantities of `mov [byte ptr foo],0` in the generated code.)
|
||||
memset_intrinsic(
|
||||
bx,
|
||||
&self,
|
||||
false,
|
||||
ty,
|
||||
llresult,
|
||||
|
@ -213,47 +211,47 @@ pub fn codegen_intrinsic_call(
|
|||
"needs_drop" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
|
||||
cx.const_bool(bx.cx().type_needs_drop(tp_ty))
|
||||
cx.const_bool(cx.type_needs_drop(tp_ty))
|
||||
}
|
||||
"offset" => {
|
||||
let ptr = args[0].immediate();
|
||||
let offset = args[1].immediate();
|
||||
bx.inbounds_gep(ptr, &[offset])
|
||||
self.inbounds_gep(ptr, &[offset])
|
||||
}
|
||||
"arith_offset" => {
|
||||
let ptr = args[0].immediate();
|
||||
let offset = args[1].immediate();
|
||||
bx.gep(ptr, &[offset])
|
||||
self.gep(ptr, &[offset])
|
||||
}
|
||||
|
||||
"copy_nonoverlapping" => {
|
||||
copy_intrinsic(bx, false, false, substs.type_at(0),
|
||||
copy_intrinsic(&self, false, false, substs.type_at(0),
|
||||
args[1].immediate(), args[0].immediate(), args[2].immediate());
|
||||
return;
|
||||
}
|
||||
"copy" => {
|
||||
copy_intrinsic(bx, true, false, substs.type_at(0),
|
||||
copy_intrinsic(&self, true, false, substs.type_at(0),
|
||||
args[1].immediate(), args[0].immediate(), args[2].immediate());
|
||||
return;
|
||||
}
|
||||
"write_bytes" => {
|
||||
memset_intrinsic(bx, false, substs.type_at(0),
|
||||
memset_intrinsic(&self, false, substs.type_at(0),
|
||||
args[0].immediate(), args[1].immediate(), args[2].immediate());
|
||||
return;
|
||||
}
|
||||
|
||||
"volatile_copy_nonoverlapping_memory" => {
|
||||
copy_intrinsic(bx, false, true, substs.type_at(0),
|
||||
copy_intrinsic(&self, false, true, substs.type_at(0),
|
||||
args[0].immediate(), args[1].immediate(), args[2].immediate());
|
||||
return;
|
||||
}
|
||||
"volatile_copy_memory" => {
|
||||
copy_intrinsic(bx, true, true, substs.type_at(0),
|
||||
copy_intrinsic(&self, true, true, substs.type_at(0),
|
||||
args[0].immediate(), args[1].immediate(), args[2].immediate());
|
||||
return;
|
||||
}
|
||||
"volatile_set_memory" => {
|
||||
memset_intrinsic(bx, true, substs.type_at(0),
|
||||
memset_intrinsic(&self, true, substs.type_at(0),
|
||||
args[0].immediate(), args[1].immediate(), args[2].immediate());
|
||||
return;
|
||||
}
|
||||
|
@ -261,9 +259,9 @@ pub fn codegen_intrinsic_call(
|
|||
let tp_ty = substs.type_at(0);
|
||||
let mut ptr = args[0].immediate();
|
||||
if let PassMode::Cast(ty) = fn_ty.ret.mode {
|
||||
ptr = bx.pointercast(ptr, bx.cx().type_ptr_to(ty.llvm_type(cx)));
|
||||
ptr = self.pointercast(ptr, cx.type_ptr_to(ty.llvm_type(cx)));
|
||||
}
|
||||
let load = bx.volatile_load(ptr);
|
||||
let load = self.volatile_load(ptr);
|
||||
let align = if name == "unaligned_volatile_load" {
|
||||
1
|
||||
} else {
|
||||
|
@ -272,16 +270,16 @@ pub fn codegen_intrinsic_call(
|
|||
unsafe {
|
||||
llvm::LLVMSetAlignment(load, align);
|
||||
}
|
||||
to_immediate(bx, load, cx.layout_of(tp_ty))
|
||||
to_immediate(self, load, cx.layout_of(tp_ty))
|
||||
},
|
||||
"volatile_store" => {
|
||||
let dst = args[0].deref(bx.cx());
|
||||
args[1].val.volatile_store(bx, dst);
|
||||
let dst = args[0].deref(cx);
|
||||
args[1].val.volatile_store(&self, dst);
|
||||
return;
|
||||
},
|
||||
"unaligned_volatile_store" => {
|
||||
let dst = args[0].deref(bx.cx());
|
||||
args[1].val.unaligned_volatile_store(bx, dst);
|
||||
let dst = args[0].deref(cx);
|
||||
args[1].val.unaligned_volatile_store(&self, dst);
|
||||
return;
|
||||
},
|
||||
"prefetch_read_data" | "prefetch_write_data" |
|
||||
|
@ -294,7 +292,7 @@ pub fn codegen_intrinsic_call(
|
|||
"prefetch_write_instruction" => (1, 0),
|
||||
_ => bug!()
|
||||
};
|
||||
bx.call(expect, &[
|
||||
self.call(expect, &[
|
||||
args[0].immediate(),
|
||||
cx.const_i32(rw),
|
||||
args[1].immediate(),
|
||||
|
@ -313,76 +311,82 @@ pub fn codegen_intrinsic_call(
|
|||
"ctlz" | "cttz" => {
|
||||
let y = cx.const_bool(false);
|
||||
let llfn = cx.get_intrinsic(&format!("llvm.{}.i{}", name, width));
|
||||
bx.call(llfn, &[args[0].immediate(), y], None)
|
||||
self.call(llfn, &[args[0].immediate(), y], None)
|
||||
}
|
||||
"ctlz_nonzero" | "cttz_nonzero" => {
|
||||
let y = cx.const_bool(true);
|
||||
let llvm_name = &format!("llvm.{}.i{}", &name[..4], width);
|
||||
let llfn = cx.get_intrinsic(llvm_name);
|
||||
bx.call(llfn, &[args[0].immediate(), y], None)
|
||||
self.call(llfn, &[args[0].immediate(), y], None)
|
||||
}
|
||||
"ctpop" => bx.call(cx.get_intrinsic(&format!("llvm.ctpop.i{}", width)),
|
||||
&[args[0].immediate()], None),
|
||||
"ctpop" => self.call(
|
||||
cx.get_intrinsic(&format!("llvm.ctpop.i{}", width)),
|
||||
&[args[0].immediate()],
|
||||
None
|
||||
),
|
||||
"bswap" => {
|
||||
if width == 8 {
|
||||
args[0].immediate() // byte swap a u8/i8 is just a no-op
|
||||
} else {
|
||||
bx.call(cx.get_intrinsic(&format!("llvm.bswap.i{}", width)),
|
||||
self.call(cx.get_intrinsic(&format!("llvm.bswap.i{}", width)),
|
||||
&[args[0].immediate()], None)
|
||||
}
|
||||
}
|
||||
"bitreverse" => {
|
||||
bx.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)),
|
||||
self.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)),
|
||||
&[args[0].immediate()], None)
|
||||
}
|
||||
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
|
||||
let intrinsic = format!("llvm.{}{}.with.overflow.i{}",
|
||||
if signed { 's' } else { 'u' },
|
||||
&name[..3], width);
|
||||
let llfn = bx.cx().get_intrinsic(&intrinsic);
|
||||
let llfn = cx.get_intrinsic(&intrinsic);
|
||||
|
||||
// Convert `i1` to a `bool`, and write it to the out parameter
|
||||
let pair = bx.call(llfn, &[
|
||||
let pair = self.call(llfn, &[
|
||||
args[0].immediate(),
|
||||
args[1].immediate()
|
||||
], None);
|
||||
let val = bx.extract_value(pair, 0);
|
||||
let overflow = bx.zext(bx.extract_value(pair, 1), cx.type_bool());
|
||||
let val = self.extract_value(pair, 0);
|
||||
let overflow = self.zext(
|
||||
self.extract_value(pair, 1),
|
||||
cx.type_bool()
|
||||
);
|
||||
|
||||
let dest = result.project_field(bx, 0);
|
||||
bx.store(val, dest.llval, dest.align);
|
||||
let dest = result.project_field(bx, 1);
|
||||
bx.store(overflow, dest.llval, dest.align);
|
||||
let dest = result.project_field(&self, 0);
|
||||
self.store(val, dest.llval, dest.align);
|
||||
let dest = result.project_field(&self, 1);
|
||||
self.store(overflow, dest.llval, dest.align);
|
||||
|
||||
return;
|
||||
},
|
||||
"overflowing_add" => bx.add(args[0].immediate(), args[1].immediate()),
|
||||
"overflowing_sub" => bx.sub(args[0].immediate(), args[1].immediate()),
|
||||
"overflowing_mul" => bx.mul(args[0].immediate(), args[1].immediate()),
|
||||
"overflowing_add" => self.add(args[0].immediate(), args[1].immediate()),
|
||||
"overflowing_sub" => self.sub(args[0].immediate(), args[1].immediate()),
|
||||
"overflowing_mul" => self.mul(args[0].immediate(), args[1].immediate()),
|
||||
"exact_div" =>
|
||||
if signed {
|
||||
bx.exactsdiv(args[0].immediate(), args[1].immediate())
|
||||
self.exactsdiv(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.exactudiv(args[0].immediate(), args[1].immediate())
|
||||
self.exactudiv(args[0].immediate(), args[1].immediate())
|
||||
},
|
||||
"unchecked_div" =>
|
||||
if signed {
|
||||
bx.sdiv(args[0].immediate(), args[1].immediate())
|
||||
self.sdiv(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.udiv(args[0].immediate(), args[1].immediate())
|
||||
self.udiv(args[0].immediate(), args[1].immediate())
|
||||
},
|
||||
"unchecked_rem" =>
|
||||
if signed {
|
||||
bx.srem(args[0].immediate(), args[1].immediate())
|
||||
self.srem(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.urem(args[0].immediate(), args[1].immediate())
|
||||
self.urem(args[0].immediate(), args[1].immediate())
|
||||
},
|
||||
"unchecked_shl" => bx.shl(args[0].immediate(), args[1].immediate()),
|
||||
"unchecked_shl" => self.shl(args[0].immediate(), args[1].immediate()),
|
||||
"unchecked_shr" =>
|
||||
if signed {
|
||||
bx.ashr(args[0].immediate(), args[1].immediate())
|
||||
self.ashr(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.lshr(args[0].immediate(), args[1].immediate())
|
||||
self.lshr(args[0].immediate(), args[1].immediate())
|
||||
},
|
||||
"rotate_left" | "rotate_right" => {
|
||||
let is_left = name == "rotate_left";
|
||||
|
@ -393,16 +397,22 @@ pub fn codegen_intrinsic_call(
|
|||
let llvm_name = &format!("llvm.fsh{}.i{}",
|
||||
if is_left { 'l' } else { 'r' }, width);
|
||||
let llfn = cx.get_intrinsic(llvm_name);
|
||||
bx.call(llfn, &[val, val, raw_shift], None)
|
||||
self.call(llfn, &[val, val, raw_shift], None)
|
||||
} else {
|
||||
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
|
||||
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
|
||||
let width = cx.const_uint(cx.type_ix(width), width);
|
||||
let shift = bx.urem(raw_shift, width);
|
||||
let inv_shift = bx.urem(bx.sub(width, raw_shift), width);
|
||||
let shift1 = bx.shl(val, if is_left { shift } else { inv_shift });
|
||||
let shift2 = bx.lshr(val, if !is_left { shift } else { inv_shift });
|
||||
bx.or(shift1, shift2)
|
||||
let shift = self.urem(raw_shift, width);
|
||||
let inv_shift = self.urem(self.sub(width, raw_shift), width);
|
||||
let shift1 = self.shl(
|
||||
val,
|
||||
if is_left { shift } else { inv_shift },
|
||||
);
|
||||
let shift2 = self.lshr(
|
||||
val,
|
||||
if !is_left { shift } else { inv_shift },
|
||||
);
|
||||
self.or(shift1, shift2)
|
||||
}
|
||||
},
|
||||
_ => bug!(),
|
||||
|
@ -415,17 +425,18 @@ pub fn codegen_intrinsic_call(
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
|
||||
let sty = &arg_tys[0].sty;
|
||||
match float_type_width(sty) {
|
||||
Some(_width) =>
|
||||
match name {
|
||||
"fadd_fast" => bx.fadd_fast(args[0].immediate(), args[1].immediate()),
|
||||
"fsub_fast" => bx.fsub_fast(args[0].immediate(), args[1].immediate()),
|
||||
"fmul_fast" => bx.fmul_fast(args[0].immediate(), args[1].immediate()),
|
||||
"fdiv_fast" => bx.fdiv_fast(args[0].immediate(), args[1].immediate()),
|
||||
"frem_fast" => bx.frem_fast(args[0].immediate(), args[1].immediate()),
|
||||
"fadd_fast" => self.fadd_fast(args[0].immediate(), args[1].immediate()),
|
||||
"fsub_fast" => self.fsub_fast(args[0].immediate(), args[1].immediate()),
|
||||
"fmul_fast" => self.fmul_fast(args[0].immediate(), args[1].immediate()),
|
||||
"fdiv_fast" => self.fdiv_fast(args[0].immediate(), args[1].immediate()),
|
||||
"frem_fast" => self.frem_fast(args[0].immediate(), args[1].immediate()),
|
||||
_ => bug!(),
|
||||
},
|
||||
None => {
|
||||
|
@ -440,11 +451,11 @@ pub fn codegen_intrinsic_call(
|
|||
},
|
||||
|
||||
"discriminant_value" => {
|
||||
args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty)
|
||||
args[0].deref(cx).codegen_get_discr(&self, ret_ty)
|
||||
}
|
||||
|
||||
name if name.starts_with("simd_") => {
|
||||
match generic_simd_intrinsic(bx, name,
|
||||
match generic_simd_intrinsic(&self, name,
|
||||
callee_ty,
|
||||
args,
|
||||
ret_ty, llret_ty,
|
||||
|
@ -496,20 +507,23 @@ pub fn codegen_intrinsic_call(
|
|||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, cx).is_some() {
|
||||
let weak = split[1] == "cxchgweak";
|
||||
let pair = bx.atomic_cmpxchg(
|
||||
let pair = self.atomic_cmpxchg(
|
||||
args[0].immediate(),
|
||||
args[1].immediate(),
|
||||
args[2].immediate(),
|
||||
order,
|
||||
failorder,
|
||||
weak);
|
||||
let val = bx.extract_value(pair, 0);
|
||||
let success = bx.zext(bx.extract_value(pair, 1), bx.cx().type_bool());
|
||||
let val = self.extract_value(pair, 0);
|
||||
let success = self.zext(
|
||||
self.extract_value(pair, 1),
|
||||
cx.type_bool()
|
||||
);
|
||||
|
||||
let dest = result.project_field(bx, 0);
|
||||
bx.store(val, dest.llval, dest.align);
|
||||
let dest = result.project_field(bx, 1);
|
||||
bx.store(success, dest.llval, dest.align);
|
||||
let dest = result.project_field(&self, 0);
|
||||
self.store(val, dest.llval, dest.align);
|
||||
let dest = result.project_field(&self, 1);
|
||||
self.store(success, dest.llval, dest.align);
|
||||
return;
|
||||
} else {
|
||||
return invalid_monomorphization(ty);
|
||||
|
@ -520,7 +534,7 @@ pub fn codegen_intrinsic_call(
|
|||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, cx).is_some() {
|
||||
let size = cx.size_of(ty);
|
||||
bx.atomic_load(args[0].immediate(), order, size)
|
||||
self.atomic_load(args[0].immediate(), order, size)
|
||||
} else {
|
||||
return invalid_monomorphization(ty);
|
||||
}
|
||||
|
@ -530,7 +544,12 @@ pub fn codegen_intrinsic_call(
|
|||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, cx).is_some() {
|
||||
let size = cx.size_of(ty);
|
||||
bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size);
|
||||
self.atomic_store(
|
||||
args[1].immediate(),
|
||||
args[0].immediate(),
|
||||
order,
|
||||
size
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
return invalid_monomorphization(ty);
|
||||
|
@ -538,12 +557,12 @@ pub fn codegen_intrinsic_call(
|
|||
}
|
||||
|
||||
"fence" => {
|
||||
bx.atomic_fence(order, SynchronizationScope::CrossThread);
|
||||
self.atomic_fence(order, SynchronizationScope::CrossThread);
|
||||
return;
|
||||
}
|
||||
|
||||
"singlethreadfence" => {
|
||||
bx.atomic_fence(order, SynchronizationScope::SingleThread);
|
||||
self.atomic_fence(order, SynchronizationScope::SingleThread);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -566,7 +585,12 @@ pub fn codegen_intrinsic_call(
|
|||
|
||||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, cx).is_some() {
|
||||
bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order)
|
||||
self.atomic_rmw(
|
||||
atom_op,
|
||||
args[0].immediate(),
|
||||
args[1].immediate(),
|
||||
order
|
||||
)
|
||||
} else {
|
||||
return invalid_monomorphization(ty);
|
||||
}
|
||||
|
@ -575,20 +599,24 @@ pub fn codegen_intrinsic_call(
|
|||
}
|
||||
|
||||
"nontemporal_store" => {
|
||||
let dst = args[0].deref(bx.cx());
|
||||
args[1].val.nontemporal_store(bx, dst);
|
||||
let dst = args[0].deref(cx);
|
||||
args[1].val.nontemporal_store(&self, dst);
|
||||
return;
|
||||
}
|
||||
|
||||
_ => {
|
||||
let intr = Intrinsic::find(&name).unwrap_or_else(||
|
||||
bug!("unknown intrinsic '{}'", name));
|
||||
|
||||
let intr = match Intrinsic::find(&name) {
|
||||
Some(intr) => intr,
|
||||
None => bug!("unknown intrinsic '{}'", name),
|
||||
};
|
||||
fn one<T>(x: Vec<T>) -> T {
|
||||
assert_eq!(x.len(), 1);
|
||||
x.into_iter().next().unwrap()
|
||||
}
|
||||
fn ty_to_type(cx: &CodegenCx<'ll, '_>, t: &intrinsics::Type) -> Vec<&'ll Type> {
|
||||
fn ty_to_type<'ll>(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
t: &intrinsics::Type
|
||||
) -> Vec<&'ll Type> {
|
||||
use intrinsics::Type::*;
|
||||
match *t {
|
||||
Void => vec![cx.type_void()],
|
||||
|
@ -630,8 +658,8 @@ pub fn codegen_intrinsic_call(
|
|||
// qux` to be converted into `foo, bar, baz, qux`, integer
|
||||
// arguments to be truncated as needed and pointers to be
|
||||
// cast.
|
||||
fn modify_as_needed(
|
||||
bx: &Builder<'a, 'll, 'tcx>,
|
||||
fn modify_as_needed<'ll, 'tcx>(
|
||||
bx: &Builder<'_, 'll, 'tcx>,
|
||||
t: &intrinsics::Type,
|
||||
arg: &OperandRef<'tcx, &'ll Value>,
|
||||
) -> Vec<&'ll Value> {
|
||||
|
@ -682,7 +710,7 @@ pub fn codegen_intrinsic_call(
|
|||
let outputs = one(ty_to_type(cx, &intr.output));
|
||||
|
||||
let llargs: Vec<_> = intr.inputs.iter().zip(args).flat_map(|(t, arg)| {
|
||||
modify_as_needed(bx, t, arg)
|
||||
modify_as_needed(&self, t, arg)
|
||||
}).collect();
|
||||
assert_eq!(inputs.len(), llargs.len());
|
||||
|
||||
|
@ -691,7 +719,7 @@ pub fn codegen_intrinsic_call(
|
|||
let f = declare::declare_cfn(cx,
|
||||
name,
|
||||
cx.type_func(&inputs, outputs));
|
||||
bx.call(f, &llargs, None)
|
||||
self.call(f, &llargs, None)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -701,9 +729,9 @@ pub fn codegen_intrinsic_call(
|
|||
assert!(!flatten);
|
||||
|
||||
for i in 0..elems.len() {
|
||||
let dest = result.project_field(bx, i);
|
||||
let val = bx.extract_value(val, i as u64);
|
||||
bx.store(val, dest.llval, dest.align);
|
||||
let dest = result.project_field(&self, i);
|
||||
let val = self.extract_value(val, i as u64);
|
||||
self.store(val, dest.llval, dest.align);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -714,11 +742,12 @@ pub fn codegen_intrinsic_call(
|
|||
|
||||
if !fn_ty.ret.is_ignore() {
|
||||
if let PassMode::Cast(ty) = fn_ty.ret.mode {
|
||||
let ptr = bx.pointercast(result.llval, cx.type_ptr_to(ty.llvm_type(cx)));
|
||||
bx.store(llval, ptr, result.align);
|
||||
let ptr = self.pointercast(result.llval, cx.type_ptr_to(ty.llvm_type(cx)));
|
||||
self.store(llval, ptr, result.align);
|
||||
} else {
|
||||
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
|
||||
.val.store(bx, result);
|
||||
OperandRef::from_immediate_or_packed_pair(&self, llval, result.layout)
|
||||
.val.store(&self, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,10 +25,7 @@ use type_of::LayoutLlvmExt;
|
|||
use type_::Type;
|
||||
use value::Value;
|
||||
|
||||
use interfaces::{
|
||||
BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
|
||||
StaticMethods,
|
||||
};
|
||||
use interfaces::*;
|
||||
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Pos;
|
||||
|
@ -560,8 +557,6 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
|
|||
};
|
||||
|
||||
if intrinsic.is_some() && intrinsic != Some("drop_in_place") {
|
||||
use intrinsic::codegen_intrinsic_call;
|
||||
|
||||
let dest = match ret_dest {
|
||||
_ if fn_ty.ret.is_indirect() => llargs[0],
|
||||
ReturnDest::Nothing => {
|
||||
|
@ -628,7 +623,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
|
|||
|
||||
|
||||
let callee_ty = instance.as_ref().unwrap().ty(bx.cx().tcx);
|
||||
codegen_intrinsic_call(&bx, callee_ty, &fn_ty, &args, dest,
|
||||
&bx.codegen_intrinsic_call(callee_ty, &fn_ty, &args, dest,
|
||||
terminator.source_info.span);
|
||||
|
||||
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
|
||||
|
|
|
@ -20,7 +20,7 @@ use value::Value;
|
|||
use type_of::LayoutLlvmExt;
|
||||
use glue;
|
||||
|
||||
use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, DerivedIntrinsicMethods};
|
||||
use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, IntrinsicDeclarationMethods};
|
||||
|
||||
use std::fmt;
|
||||
|
||||
|
|
|
@ -21,10 +21,7 @@ use value::Value;
|
|||
use glue;
|
||||
use mir::constant::const_alloc_to_llvm;
|
||||
|
||||
use interfaces::{
|
||||
BuilderMethods, ConstMethods, BaseTypeMethods, DerivedTypeMethods, DerivedIntrinsicMethods,
|
||||
StaticMethods,
|
||||
};
|
||||
use interfaces::*;
|
||||
|
||||
use super::{FunctionCx, LocalRef};
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
|
|
|
@ -25,7 +25,7 @@ use type_::Type;
|
|||
use type_of::LayoutLlvmExt;
|
||||
use value::Value;
|
||||
|
||||
use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, DerivedIntrinsicMethods};
|
||||
use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, IntrinsicDeclarationMethods};
|
||||
|
||||
use super::{FunctionCx, LocalRef};
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue