Use LLVM intrinsics for saturating add/sub
This commit is contained in:
parent
d8a0dd7ae8
commit
4a4186e4d1
5 changed files with 101 additions and 3 deletions
|
|
@ -757,6 +757,30 @@ impl CodegenCx<'b, 'tcx> {
|
|||
ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1});
|
||||
ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1});
|
||||
|
||||
ifn!("llvm.sadd.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.sadd.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.sadd.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.sadd.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.sadd.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.uadd.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.uadd.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.uadd.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.uadd.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.uadd.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.ssub.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.ssub.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.ssub.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.ssub.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.ssub.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.usub.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.usub.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.usub.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void);
|
||||
ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use type_::Type;
|
|||
use type_of::LayoutLlvmExt;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
|
||||
use rustc_codegen_ssa::common::TypeKind;
|
||||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||
use rustc::hir;
|
||||
use syntax::ast::{self, FloatTy};
|
||||
use syntax::symbol::Symbol;
|
||||
|
|
@ -28,7 +28,7 @@ use rustc::session::Session;
|
|||
use syntax_pos::Span;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::iter;
|
||||
use std::{iter, i128, u128};
|
||||
|
||||
fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
|
||||
let llvm_name = match name {
|
||||
|
|
@ -342,7 +342,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
"bitreverse" | "add_with_overflow" | "sub_with_overflow" |
|
||||
"mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
|
||||
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
|
||||
"rotate_left" | "rotate_right" => {
|
||||
"rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => {
|
||||
let ty = arg_tys[0];
|
||||
match int_type_width_signed(ty, self) {
|
||||
Some((width, signed)) =>
|
||||
|
|
@ -468,6 +468,44 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
self.or(shift1, shift2)
|
||||
}
|
||||
},
|
||||
"saturating_add" | "saturating_sub" => {
|
||||
let is_add = name == "saturating_add";
|
||||
let lhs = args[0].immediate();
|
||||
let rhs = args[1].immediate();
|
||||
if llvm_util::get_major_version() >= 8 {
|
||||
let llvm_name = &format!("llvm.{}{}.sat.i{}",
|
||||
if signed { 's' } else { 'u' },
|
||||
if is_add { "add" } else { "sub" },
|
||||
width);
|
||||
let llfn = self.get_intrinsic(llvm_name);
|
||||
self.call(llfn, &[lhs, rhs], None)
|
||||
} else {
|
||||
let llvm_name = &format!("llvm.{}{}.with.overflow.i{}",
|
||||
if signed { 's' } else { 'u' },
|
||||
if is_add { "add" } else { "sub" },
|
||||
width);
|
||||
let llfn = self.get_intrinsic(llvm_name);
|
||||
let pair = self.call(llfn, &[lhs, rhs], None);
|
||||
let val = self.extract_value(pair, 0);
|
||||
let overflow = self.extract_value(pair, 1);
|
||||
let llty = self.type_ix(width);
|
||||
|
||||
let limit = if signed {
|
||||
let limit_lo = self.const_uint_big(
|
||||
llty, (i128::MIN >> (128 - width)) as u128);
|
||||
let limit_hi = self.const_uint_big(
|
||||
llty, (i128::MAX >> (128 - width)) as u128);
|
||||
let neg = self.icmp(
|
||||
IntPredicate::IntSLT, val, self.const_uint(llty, 0));
|
||||
self.select(neg, limit_hi, limit_lo)
|
||||
} else if is_add {
|
||||
self.const_uint_big(llty, u128::MAX >> (128 - width))
|
||||
} else {
|
||||
self.const_uint(llty, 0)
|
||||
};
|
||||
self.select(overflow, limit, val)
|
||||
}
|
||||
},
|
||||
_ => bug!(),
|
||||
},
|
||||
None => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue