Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for unchecked math #59148

Merged
merged 4 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,21 @@ extern "rust-intrinsic" {
/// y < 0 or y >= N, where N is the width of T in bits.
pub fn unchecked_shr<T>(x: T, y: T) -> T;

/// Returns the result of an unchecked addition, resulting in
/// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`.
#[cfg(not(stage0))]
pub fn unchecked_add<T>(x: T, y: T) -> T;

/// Returns the result of an unchecked substraction, resulting in
/// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`.
#[cfg(not(stage0))]
pub fn unchecked_sub<T>(x: T, y: T) -> T;

/// Returns the result of an unchecked multiplication, resulting in
/// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`.
#[cfg(not(stage0))]
pub fn unchecked_mul<T>(x: T, y: T) -> T;

/// Performs rotate left.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_left` method. For example,
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_codegen_llvm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
neg(x) => LLVMBuildNeg,
fneg(x) => LLVMBuildFNeg,
not(x) => LLVMBuildNot,
unchecked_sadd(x, y) => LLVMBuildNSWAdd,
unchecked_uadd(x, y) => LLVMBuildNUWAdd,
unchecked_ssub(x, y) => LLVMBuildNSWSub,
unchecked_usub(x, y) => LLVMBuildNUWSub,
unchecked_smul(x, y) => LLVMBuildNSWMul,
unchecked_umul(x, y) => LLVMBuildNUWMul,
}

fn fadd_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
Expand Down
24 changes: 23 additions & 1 deletion src/librustc_codegen_llvm/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
"ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
"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" |
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" |
"unchecked_add" | "unchecked_sub" | "unchecked_mul" | "exact_div" |
"rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => {
let ty = arg_tys[0];
match int_type_width_signed(ty, self) {
Expand Down Expand Up @@ -430,6 +431,27 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
} else {
self.lshr(args[0].immediate(), args[1].immediate())
},
"unchecked_add" => {
if signed {
self.unchecked_sadd(args[0].immediate(), args[1].immediate())
} else {
self.unchecked_uadd(args[0].immediate(), args[1].immediate())
}
},
"unchecked_sub" => {
if signed {
self.unchecked_ssub(args[0].immediate(), args[1].immediate())
} else {
self.unchecked_usub(args[0].immediate(), args[1].immediate())
}
},
"unchecked_mul" => {
if signed {
self.unchecked_smul(args[0].immediate(), args[1].immediate())
} else {
self.unchecked_umul(args[0].immediate(), args[1].immediate())
}
},
"rotate_left" | "rotate_right" => {
let is_left = name == "rotate_left";
let val = args[0].immediate();
Expand Down
30 changes: 30 additions & 0 deletions src/librustc_codegen_llvm/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,36 @@ extern "C" {
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
pub fn LLVMBuildNSWAdd(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
pub fn LLVMBuildNUWAdd(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
pub fn LLVMBuildNSWSub(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
pub fn LLVMBuildNUWSub(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
pub fn LLVMBuildNSWMul(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
pub fn LLVMBuildNUWMul(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
pub fn LLVMBuildAnd(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_codegen_ssa/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn unchecked_ssub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn unchecked_usub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn unchecked_smul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
"unchecked_shl" | "unchecked_shr" |
"rotate_left" | "rotate_right" =>
(1, vec![param(0), param(0)], param(0)),

"unchecked_add" | "unchecked_sub" | "unchecked_mul" =>
(1, vec![param(0), param(0)], param(0)),
"overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
(1, vec![param(0), param(0)], param(0)),
"saturating_add" | "saturating_sub" =>
Expand Down
46 changes: 46 additions & 0 deletions src/test/codegen/unchecked_math.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#![crate_type = "lib"]
#![feature(core_intrinsics)]

use std::intrinsics::*;

// CHECK-LABEL: @unchecked_add_signed
#[no_mangle]
pub unsafe fn unchecked_add_signed(a: i32, b: i32) -> i32 {
// CHECK: add nsw
unchecked_add(a, b)
}

// CHECK-LABEL: @unchecked_add_unsigned
#[no_mangle]
pub unsafe fn unchecked_add_unsigned(a: u32, b: u32) -> u32 {
// CHECK: add nuw
unchecked_add(a, b)
}

// CHECK-LABEL: @unchecked_sub_signed
#[no_mangle]
pub unsafe fn unchecked_sub_signed(a: i32, b: i32) -> i32 {
// CHECK: sub nsw
unchecked_sub(a, b)
}

// CHECK-LABEL: @unchecked_sub_unsigned
#[no_mangle]
pub unsafe fn unchecked_sub_unsigned(a: u32, b: u32) -> u32 {
// CHECK: sub nuw
unchecked_sub(a, b)
}

// CHECK-LABEL: @unchecked_mul_signed
#[no_mangle]
pub unsafe fn unchecked_mul_signed(a: i32, b: i32) -> i32 {
// CHECK: mul nsw
unchecked_mul(a, b)
}

// CHECK-LABEL: @unchecked_mul_unsigned
#[no_mangle]
pub unsafe fn unchecked_mul_unsigned(a: u32, b: u32) -> u32 {
// CHECK: mul nuw
unchecked_mul(a, b)
}
8 changes: 8 additions & 0 deletions src/test/ui/intrinsics/unchecked_math_unsafe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#![feature(core_intrinsics)]

fn main() {
let (x, y) = (1u32, 2u32);
let add = std::intrinsics::unchecked_add(x, y); //~ ERROR call to unsafe function
let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR call to unsafe function
let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR call to unsafe function
}
27 changes: 27 additions & 0 deletions src/test/ui/intrinsics/unchecked_math_unsafe.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> $DIR/unchecked_math_unsafe.rs:5:15
|
LL | let add = std::intrinsics::unchecked_add(x, y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior

error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> $DIR/unchecked_math_unsafe.rs:6:15
|
LL | let sub = std::intrinsics::unchecked_sub(x, y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior

error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> $DIR/unchecked_math_unsafe.rs:7:15
|
LL | let mul = std::intrinsics::unchecked_mul(x, y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0133`.
8 changes: 8 additions & 0 deletions src/test/ui/intrinsics/unchecked_math_unstable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn main() {
let (x, y) = (1u32, 2u32);
unsafe {
let add = std::intrinsics::unchecked_add(x, y); //~ ERROR use of unstable library feature
let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR use of unstable library feature
let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR use of unstable library feature
}
}
27 changes: 27 additions & 0 deletions src/test/ui/intrinsics/unchecked_math_unstable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
--> $DIR/unchecked_math_unstable.rs:4:19
|
LL | let add = std::intrinsics::unchecked_add(x, y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(core_intrinsics)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
--> $DIR/unchecked_math_unstable.rs:5:19
|
LL | let sub = std::intrinsics::unchecked_sub(x, y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(core_intrinsics)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
--> $DIR/unchecked_math_unstable.rs:6:19
|
LL | let mul = std::intrinsics::unchecked_mul(x, y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(core_intrinsics)] to the crate attributes to enable

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0658`.