Skip to content

Commit e22b7a3

Browse files
committed
Auto merge of #59148 - lcnr:unchecked_maths, r=eddyb
add support for unchecked math add compiler support for ```rust /// Returns the result of an unchecked addition, resulting in /// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`. 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()`. 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()`. pub fn unchecked_mul<T>(x: T, y: T) -> T; ``` cc rust-lang/rfcs#2508
2 parents 6ffb8f5 + d7e0834 commit e22b7a3

File tree

11 files changed

+198
-2
lines changed

11 files changed

+198
-2
lines changed

src/libcore/intrinsics.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,21 @@ extern "rust-intrinsic" {
12401240
/// y < 0 or y >= N, where N is the width of T in bits.
12411241
pub fn unchecked_shr<T>(x: T, y: T) -> T;
12421242

1243+
/// Returns the result of an unchecked addition, resulting in
1244+
/// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`.
1245+
#[cfg(not(stage0))]
1246+
pub fn unchecked_add<T>(x: T, y: T) -> T;
1247+
1248+
/// Returns the result of an unchecked substraction, resulting in
1249+
/// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`.
1250+
#[cfg(not(stage0))]
1251+
pub fn unchecked_sub<T>(x: T, y: T) -> T;
1252+
1253+
/// Returns the result of an unchecked multiplication, resulting in
1254+
/// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`.
1255+
#[cfg(not(stage0))]
1256+
pub fn unchecked_mul<T>(x: T, y: T) -> T;
1257+
12431258
/// Performs rotate left.
12441259
/// The stabilized versions of this intrinsic are available on the integer
12451260
/// primitives via the `rotate_left` method. For example,

src/librustc_codegen_llvm/builder.rs

+6
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,12 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
265265
neg(x) => LLVMBuildNeg,
266266
fneg(x) => LLVMBuildFNeg,
267267
not(x) => LLVMBuildNot,
268+
unchecked_sadd(x, y) => LLVMBuildNSWAdd,
269+
unchecked_uadd(x, y) => LLVMBuildNUWAdd,
270+
unchecked_ssub(x, y) => LLVMBuildNSWSub,
271+
unchecked_usub(x, y) => LLVMBuildNUWSub,
272+
unchecked_smul(x, y) => LLVMBuildNSWMul,
273+
unchecked_umul(x, y) => LLVMBuildNUWMul,
268274
}
269275

270276
fn fadd_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {

src/librustc_codegen_llvm/intrinsic.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
334334
"ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
335335
"bitreverse" | "add_with_overflow" | "sub_with_overflow" |
336336
"mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
337-
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
337+
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" |
338+
"unchecked_add" | "unchecked_sub" | "unchecked_mul" | "exact_div" |
338339
"rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => {
339340
let ty = arg_tys[0];
340341
match int_type_width_signed(ty, self) {
@@ -430,6 +431,27 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
430431
} else {
431432
self.lshr(args[0].immediate(), args[1].immediate())
432433
},
434+
"unchecked_add" => {
435+
if signed {
436+
self.unchecked_sadd(args[0].immediate(), args[1].immediate())
437+
} else {
438+
self.unchecked_uadd(args[0].immediate(), args[1].immediate())
439+
}
440+
},
441+
"unchecked_sub" => {
442+
if signed {
443+
self.unchecked_ssub(args[0].immediate(), args[1].immediate())
444+
} else {
445+
self.unchecked_usub(args[0].immediate(), args[1].immediate())
446+
}
447+
},
448+
"unchecked_mul" => {
449+
if signed {
450+
self.unchecked_smul(args[0].immediate(), args[1].immediate())
451+
} else {
452+
self.unchecked_umul(args[0].immediate(), args[1].immediate())
453+
}
454+
},
433455
"rotate_left" | "rotate_right" => {
434456
let is_left = name == "rotate_left";
435457
let val = args[0].immediate();

src/librustc_codegen_llvm/llvm/ffi.rs

+30
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,36 @@ extern "C" {
10021002
RHS: &'a Value,
10031003
Name: *const c_char)
10041004
-> &'a Value;
1005+
pub fn LLVMBuildNSWAdd(B: &Builder<'a>,
1006+
LHS: &'a Value,
1007+
RHS: &'a Value,
1008+
Name: *const c_char)
1009+
-> &'a Value;
1010+
pub fn LLVMBuildNUWAdd(B: &Builder<'a>,
1011+
LHS: &'a Value,
1012+
RHS: &'a Value,
1013+
Name: *const c_char)
1014+
-> &'a Value;
1015+
pub fn LLVMBuildNSWSub(B: &Builder<'a>,
1016+
LHS: &'a Value,
1017+
RHS: &'a Value,
1018+
Name: *const c_char)
1019+
-> &'a Value;
1020+
pub fn LLVMBuildNUWSub(B: &Builder<'a>,
1021+
LHS: &'a Value,
1022+
RHS: &'a Value,
1023+
Name: *const c_char)
1024+
-> &'a Value;
1025+
pub fn LLVMBuildNSWMul(B: &Builder<'a>,
1026+
LHS: &'a Value,
1027+
RHS: &'a Value,
1028+
Name: *const c_char)
1029+
-> &'a Value;
1030+
pub fn LLVMBuildNUWMul(B: &Builder<'a>,
1031+
LHS: &'a Value,
1032+
RHS: &'a Value,
1033+
Name: *const c_char)
1034+
-> &'a Value;
10051035
pub fn LLVMBuildAnd(B: &Builder<'a>,
10061036
LHS: &'a Value,
10071037
RHS: &'a Value,

src/librustc_codegen_ssa/traits/builder.rs

+6
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
8888
fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
8989
fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
9090
fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
91+
fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
92+
fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
93+
fn unchecked_ssub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
94+
fn unchecked_usub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
95+
fn unchecked_smul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
96+
fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
9197
fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
9298
fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
9399
fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;

src/librustc_typeck/check/intrinsic.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
305305
"unchecked_shl" | "unchecked_shr" |
306306
"rotate_left" | "rotate_right" =>
307307
(1, vec![param(0), param(0)], param(0)),
308-
308+
"unchecked_add" | "unchecked_sub" | "unchecked_mul" =>
309+
(1, vec![param(0), param(0)], param(0)),
309310
"overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
310311
(1, vec![param(0), param(0)], param(0)),
311312
"saturating_add" | "saturating_sub" =>

src/test/codegen/unchecked_math.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![crate_type = "lib"]
2+
#![feature(core_intrinsics)]
3+
4+
use std::intrinsics::*;
5+
6+
// CHECK-LABEL: @unchecked_add_signed
7+
#[no_mangle]
8+
pub unsafe fn unchecked_add_signed(a: i32, b: i32) -> i32 {
9+
// CHECK: add nsw
10+
unchecked_add(a, b)
11+
}
12+
13+
// CHECK-LABEL: @unchecked_add_unsigned
14+
#[no_mangle]
15+
pub unsafe fn unchecked_add_unsigned(a: u32, b: u32) -> u32 {
16+
// CHECK: add nuw
17+
unchecked_add(a, b)
18+
}
19+
20+
// CHECK-LABEL: @unchecked_sub_signed
21+
#[no_mangle]
22+
pub unsafe fn unchecked_sub_signed(a: i32, b: i32) -> i32 {
23+
// CHECK: sub nsw
24+
unchecked_sub(a, b)
25+
}
26+
27+
// CHECK-LABEL: @unchecked_sub_unsigned
28+
#[no_mangle]
29+
pub unsafe fn unchecked_sub_unsigned(a: u32, b: u32) -> u32 {
30+
// CHECK: sub nuw
31+
unchecked_sub(a, b)
32+
}
33+
34+
// CHECK-LABEL: @unchecked_mul_signed
35+
#[no_mangle]
36+
pub unsafe fn unchecked_mul_signed(a: i32, b: i32) -> i32 {
37+
// CHECK: mul nsw
38+
unchecked_mul(a, b)
39+
}
40+
41+
// CHECK-LABEL: @unchecked_mul_unsigned
42+
#[no_mangle]
43+
pub unsafe fn unchecked_mul_unsigned(a: u32, b: u32) -> u32 {
44+
// CHECK: mul nuw
45+
unchecked_mul(a, b)
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(core_intrinsics)]
2+
3+
fn main() {
4+
let (x, y) = (1u32, 2u32);
5+
let add = std::intrinsics::unchecked_add(x, y); //~ ERROR call to unsafe function
6+
let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR call to unsafe function
7+
let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR call to unsafe function
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
2+
--> $DIR/unchecked_math_unsafe.rs:5:15
3+
|
4+
LL | let add = std::intrinsics::unchecked_add(x, y);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
6+
|
7+
= note: consult the function's documentation for information on how to avoid undefined behavior
8+
9+
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
10+
--> $DIR/unchecked_math_unsafe.rs:6:15
11+
|
12+
LL | let sub = std::intrinsics::unchecked_sub(x, y);
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
14+
|
15+
= note: consult the function's documentation for information on how to avoid undefined behavior
16+
17+
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
18+
--> $DIR/unchecked_math_unsafe.rs:7:15
19+
|
20+
LL | let mul = std::intrinsics::unchecked_mul(x, y);
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
22+
|
23+
= note: consult the function's documentation for information on how to avoid undefined behavior
24+
25+
error: aborting due to 3 previous errors
26+
27+
For more information about this error, try `rustc --explain E0133`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
let (x, y) = (1u32, 2u32);
3+
unsafe {
4+
let add = std::intrinsics::unchecked_add(x, y); //~ ERROR use of unstable library feature
5+
let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR use of unstable library feature
6+
let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR use of unstable library feature
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
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
2+
--> $DIR/unchecked_math_unstable.rs:4:19
3+
|
4+
LL | let add = std::intrinsics::unchecked_add(x, y);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add #![feature(core_intrinsics)] to the crate attributes to enable
8+
9+
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
10+
--> $DIR/unchecked_math_unstable.rs:5:19
11+
|
12+
LL | let sub = std::intrinsics::unchecked_sub(x, y);
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
|
15+
= help: add #![feature(core_intrinsics)] to the crate attributes to enable
16+
17+
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
18+
--> $DIR/unchecked_math_unstable.rs:6:19
19+
|
20+
LL | let mul = std::intrinsics::unchecked_mul(x, y);
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
|
23+
= help: add #![feature(core_intrinsics)] to the crate attributes to enable
24+
25+
error: aborting due to 3 previous errors
26+
27+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)